Jump to content
mindplay.dk

"Continuous integration" of Field and Template changes

Recommended Posts

Greetings Everyone,

Just to confirm: if you have a completed site, you can pack it up and redeploy it in its entirety, correct? Isn't that how we have installable "profiles" like SkyScrapers?

So we are just talking about incremental changes to a site?

Thanks,

Matthew

Share this post


Link to post
Share on other sites

Yes we're talking about how small changes to a site, as it is being built/adapted in a development environment, can then be mirrored safely to a "live" site.

Share this post


Link to post
Share on other sites
It might be possible to at least figure out some guidelines to help people know how to manually export SQL at one end and then import the right bits at the other end.

I recently tried and gave up - many field-types actually store things in the "pages" table, so if somebody created a new page of content on the site while you were working on a local copy, you'll have overlapping page IDs.

In the end, I had to tell people to back off the site while I was working locally and wait for me to signal the green flag - then replicate all the changes by hand.

Ideally, I would like a module that provides automated one-click deployment and version control for all metadata, which, fortunately, thanks to good clean data architecture in PW, can be done by just handling Templates and Fields.

I wonder, would anybody be interested in this module as a commercial option?

  • Like 2

Share this post


Link to post
Share on other sites
many field-types actually store things in the "pages" table, so if somebody created a new page of content on the site while you were working on a local copy, you'll have overlapping page IDs.

The two one would have to consider are:

  • Page Fieldtype -- keeps track of an ID from the pages table, if you choose to use the "parent" as the criteria for selectable pages. It doesn't add anything to the pages table, it just keeps track of an ID already in there.
  • Repeater Fieldtype -- This one actually generates pages as you mentioned (and it's the only I'm aware of that does).

Any continuous integration tool would probably want to exclude these two, or at least the Repeater one, until version 2+. :)

I wonder, would anybody be interested in this module as a commercial option?

I think it fits the commercial option well. 

My plan is to add JSON import/export to templates and fields very soon (very much like what's in FormBuilder). But this is just a quicker way of doing it manually (copy/paste vs. doing the work), it doesn't have the scope of a fully automated deployment tool. 

  • Like 5

Share this post


Link to post
Share on other sites
I am a little closer to 'kind of' this, but it's… not done yet :)

What do you mean, are you working on a module too?

Share this post


Link to post
Share on other sites

Yeah, but veeeeeery slowly :)

and what I try to do is less auto-magical and more like rails migrations (i hope).

Share this post


Link to post
Share on other sites

I would happily pay a lot of money for a comercial module that solves this problem. I am sure a lot of other freelancers and agencies would too, once the benefits of the process are clearly explained. Maybe you could also combine it with a good backup solution - "painless deployment and backups - save time and headaches when developing and iterating rapidly changing client projects"

  • Like 2

Share this post


Link to post
Share on other sites

Definitely money worth module, given it is implemented right. 

  • Like 1

Share this post


Link to post
Share on other sites

This solves a particular pain and saves much time, so it's worth money.

  • Like 1

Share this post


Link to post
Share on other sites

What if there's a problem.

So you would need to have a test before, and backup all data before. And if deploying to a live site, you'd have to disable it first too in case. I can see this could cause also more time and trouble than doing it manually anyway. Depends a lot on what you need to change or implement. Doing just template/field synchronizing maybe a good way to start and can save time, but a full blown deploy tool I hardly would trust in it and have always fear it doesn't work and causing more work at the end. There's so many things to consider and what can go wrong will go wrong.

I think we'd all love some sort of such a feature anyway. Even if it's just export template/fields and import them in a save way.

Share this post


Link to post
Share on other sites

I ment if it saves time. I should be more careful posting :)

I agree that

There's so many things to consider and what can go wrong will go wrong.

And often timesavers up front costs often costs more time afterwards. Therefore it really depends on the implemantation. Since I am not very techinal, I've read mindplay.dk's words as an automated deploy/sync tool. Which sounds like a timesaver to me. If it saves me time I have no problem buying this.

Share this post


Link to post
Share on other sites
Doing just template/field synchronizing maybe a good way to start and can save time, but a full blown deploy tool I hardly would trust in it and have always fear it doesn't work and causing more work at the end. 

Agreed, that's not what I'm aiming for - this tool would provide continuous integration of template/field changes only, not for content.

An import/export tool would be much safer and more useful for content, I think?

An import/export tool for templates/fields, on the other hand, would not feel very safe to me, personally - there is an long list of possible problems to deal with (template/field name collisions, renamed templates or fields, missing fields, etc.) and a much longer list of possible ways to resolve those problems, many of which you would need to ask the user to select on a case-by-case basis. It sounds like a scary idea to me.

In a continuous integration module for templates/fields, advance consistency checks could be implemented fairly easily - e.g. by maintaining a serial number and checksums for the change-sets, so that (in effect) one installation is designated "master" and can only push the next change-set to a "slave" in the right order.

This would not be a magical tool that somehow resolves conflicts between template/field versions that are out of sync - it would guarantee reproducible result simply by preventing change-sets from being applied out of order.

In other words, this would be designed for a workflow where you have (for example) a development server pushing changes to a production server, where the client would be permitted to edit the content, but not the templates/fields.

I wonder if pushing or pulling would be the most durable approach. Perhaps pulling would be safer, and perhaps then pulling change-sets out of order could even be permitted, with a warning, so that one developer could pull another developer's changes on demand, and on success, the combined changes could then safely be pulled up to a production server...

Share this post


Link to post
Share on other sites

I just stumbled upon this topic by now and this is definitely something that I didn't find a convincing solution for in all CMS I've tried and would love to use (and also wouldn't mind paying for, if done right).

The scenario you pointed out is what I believe to be the most common, having a two or three different instances of the site, local dev,  probably staging and production and only wanting to work on the field/template schema data.

Wouldn't it then be sufficient to have a tool to export your field/template schema data to a file and safely reimport them, so you can make it part of your version control? This should even be more secure than the idea of logging changes, which might be a problem if you have several developers working on local dev versions.

Share this post


Link to post
Share on other sites

I have shell scripts to copy the live site to the dev. I could see a tool to export and import content. So it would be possible to work on dev, and let editor edit content on live site. Then reimport content from live to dev, before pushing all from dev to live. But this can give conflicts with content created on live, while at the same time maybe adding content to on dev version. So maybe prone to errors.

Really don't know what could be done and in what way, I just know it's very hard to bring a solution, and there hardly any CMS that has this functionalities for a good reason. Migrating content is not what I mean which is easy.

Share this post


Link to post
Share on other sites
there hardly any CMS that has this functionalities for a good reason.

What complicates this in other CMS, is the fact that (at large) they don't have a unified data-model for the metadata (templates/fields) - lots of extensions create their own tables. This is very rarely necessary (and shouldn't be) in PW, where the data-model was designed from the ground up to support the entire metadata-model.

I think this would be much simpler to implement in PW than in any other CMS.

  • Like 1

Share this post


Link to post
Share on other sites
Wouldn't it then be sufficient to have a tool to export your field/template schema data to a file and safely reimport them, so you can make it part of your version control? This should even be more secure than the idea of logging changes, which might be a problem if you have several developers working on local dev versions.

In my experience, no.

If two developers are working on local dev versions, they have to be careful about what they import/export when they're done - if you worked on "foo", and I accidentally export "foo", if I deploy after you, your changes will be lost.

Logging repeatable changes is probably safer - this is essentially what database schema migration systems and source-control systems do, and most of the time, assuming two developers coordinate what they're doing just a little bit, this rarely causes any conflicts.

I'm not saying this would be dead simple to implement - there would be challenges, for sure, but I think it's possible.

Share this post


Link to post
Share on other sites

@ryan

I'm taking another look at this, and running into a problem. It appears there is no way to enumerate Field settings?

If I may suggest a small change in the Field class:

	/**
	 * Get a Field setting or dynamic data property
	 *
	 */
	public function get($key) {
		if($key == 'table') return $this->getTable();
			else if($key == 'prevTable') return $this->prevTable; 
			else if($key == 'prevFieldtype') return $this->prevFieldtype; 
			else if(isset($this->settings[$key])) return $this->settings[$key];
			else if($key == 'settings') return $this->settings; # <- ! 
		return parent::get($key); 
	}

Or perhaps more explicit, and without the risk of colliding with a setting called 'settings', a method like getSettings() would do the trick, too.

What do you think?

  • Like 1

Share this post


Link to post
Share on other sites
I'm taking another look at this, and running into a problem. It appears there is no way to enumerate Field settings?

You should be able to use the $field->getTableData() function. In addition to what is in $settings, it will also have a 'data' property which is an array containing any custom field settings. Let me know if that doesn't provide what you need?

Share this post


Link to post
Share on other sites
You should be able to use the $field->getTableData() function. In addition to what is in $settings, it will also have a 'data' property which is an array containing any custom field settings. Let me know if that doesn't provide what you need?

Yep, I backtracked through the code last night, and that's what I ended up using :)

Lots of details to work out still, but it looks like every create/update/delete of Fields is now being captured correctly.

Computing the difference between the previous and updated versions of Fields is tricky - the types seem to change? For example, the width (the 0-100 integer value) doesn't seem to be available initially after load (?) ... and to compute the difference, I now use != instead of !== which cleared out a lot of unnecessary values that would otherwise register as updated because they change e.g. from a string like '100' to an integer...

Share this post


Link to post
Share on other sites

You should have the changes available in $page->trackChanges() ?

Edit: or foreach and use $page->isChanged('field') for each field.

Share this post


Link to post
Share on other sites
You should have the changes available in $page->trackChanges() ?

Edit: or foreach and use $page->isChanged('field') for each field.

@ryan will that work for $settings in the Field class? I poked through the code, but I wasn't sure this would work for every attribute...

Share this post


Link to post
Share on other sites
Computing the difference between the previous and updated versions of Fields is tricky - the types seem to change? For example, the width (the 0-100 integer value) doesn't seem to be available initially after load (?) ... and to compute the difference, I now use != instead of !== which cleared out a lot of unnecessary values that would otherwise register as updated because they change e.g. from a string like '100' to an integer...

Only non-zero values are stored. It removes zero-based values before saving them (less storage redundancy). In the case of the field you mentioned, "100" means "100%" which means "full-width". We actually store that as 0, since it is the default value for inputfield width. So in this case, it's not being stored since it is the default when it hasn't been specifically set. 

@ryan will that work for $settings in the Field class? I poked through the code, but I wasn't sure this would work for every attribute...

It should, but I've not confirmed that. This is one case where it doesn't matter to PW much because it saves them as a group either way. So maybe it's not a good thing to rely upon here, unless you can test ahead of time to make sure it's reporting them how you want.

Share this post


Link to post
Share on other sites

I will do some experiments with trackChanges() when I have time, and report the results here...

  • Like 1

Share this post


Link to post
Share on other sites

I gave it a shot, and it doesn't work any better - for example, $collapse and $columnWidth and something called $clone_field is reported as having changed every time.

I also have the following concern:

If I set $trackChanges=true when the Field or Template is loaded, and some other module attempts to track changes, that module may be tracking more changes than it intended - and conversely, it may be setting $trackChanges=false sooner than expected by my module. It doesn't sound like that's going to work?

Furthermore, I've seen in a bunch of places things like trackChange('unset:'.$name) which suggests that some of the keys in $changes may not actually be property-names? - so I would have to somehow whitelist the keys I get back from $changes to make sure I only pick up actual properties.

It's starting to sound like more work than what I'm currently doing, and sounds like this approach may be more error-prone as well?

Unless you disagree with those assertions, I think I will stick with my current approach - it's not as elegant, but it seems safer and less likely to disrupt anything else...

Share this post


Link to post
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...