Introduction
============
This product aims to simplify running and writing third-party Generic Setup
upgrade steps in Plone.
It provides a control panel for running multiple upgrades
at once, based on the upgrade mechanism of Generic Setup (portal_setup).
Further a base class for writing upgrade steps with a variety of
helpers for common tasks is provided.
.. contents:: Table of Contents
.. figure:: http://onegov.ch/approved.png/image
:align: right
:target: http://onegov.ch/community/zertifizierte-module/ftw.upgrade
Certified: 01/2013
Features
========
* **Managing upgrades**: Provides an advanced view for upgrading
third-party Plone packages using Generic Setup.
It enables upgrading multiple packages at once with an easy to use user
interface.
By resolving the dependency graph it is able to optimize the upgrade
step order so that the upgrade is hassle free.
* **Writing upgrades**: The package provides a base upgrade class with
various helpers for common upgrade tasks.
* **Upgrade directories with less ZCML**: By registering a directory
as upgrade-directory, no additional ZCML is needed for each upgrade step.
By using a timestamp as version number we have less (merge-) conflicts
and less error potential.
* **Import profile upgrade steps**: Sometimes an upgrade step consists
solely of importing a purpose-made generic setup profile. A new
``upgrade-step:importProfile`` ZCML directive makes this much simpler.
Installation
============
- Install ``ftw.upgrade`` by adding it to the list of eggs in your buildout.
Then run buildout and restart your instance:
.. code:: ini
[instance]
eggs +=
ftw.upgrade
- Go to Site Setup of your Plone site and activate the ``ftw.upgrade`` add-on.
.. _`console script installation`:
Installing ftw.upgrade's console script
---------------------------------------
If you include ``ftw.upgrade`` in the list of ``eggs`` of a
``plone.recipe.zope2instance`` based section, the ``bin/upgrade`` script
should be generated automatically for you (that is, if you haven't limited or
suppressed script generation via the ``scripts`` option).
Otherwise, installing the console script ``bin/upgrade`` can be done with an
additional buildout part:
.. code:: ini
[buildout]
parts += upgrade
[upgrade]
recipe = zc.recipe.egg:scripts
eggs = ftw.upgrade
Compatibility
-------------
Compatible with Plone 4.3.x and 5.1.x.
Manage upgrades
===============
The ``@@manage-upgrades`` view allows to upgrade multiple packages at once:
.. image:: https://github.com/4teamwork/ftw.upgrade/raw/master/docs/manage-upgrades.png
Fallback view
-------------
The ``@@manage-upgrades-plain`` view acts as a fallback view for ``@@manage-upgrades``.
It does not include plone`s main template and thus might be able to render when the default
view fails for some reason.
The bin/upgrade script
======================
Refer to the `console script installation`_ section for instructions on how
to install ``bin/upgrade``.
The ``bin/upgrade`` console script enables management of upgrades on the filesystem
(creating new upgrades, changing upgrade order) as well as interacting with an installed
Plone site, listing profiles and upgrades and installing upgrades.
Some examples:
.. code:: sh
$ bin/upgrade create "AddCatalogIndex"
$ bin/upgrade touch my/package/upgrades/20110101000000_add_catalog_index
$ bin/upgrade sites
$ bin/upgrade list -s Plone --auth admin:admin --upgrades
$ bin/upgrade install -s Plone --auth admin:admin --proposed --intermediate-commit
The full documentation of the ``bin/upgrade`` script is available using its help system:
.. code:: sh
$ bin/upgrade help
Upgrade step helpers
====================
The ``UpgradeStep`` base class provides various tools and helpers useful
when writing upgrade steps.
It can be used by registering the classmethod directly.
Be aware that the class is very special: it acts like a function and calls
itself automatically.
Example upgrade step definition (defined in a ``upgrades.py``):
.. code:: python
from ftw.upgrade import UpgradeStep
class UpdateFooIndex(UpgradeStep):
"""The index ``foo`` is a ``FieldIndex`` instead of a
``KeywordIndex``. This upgrade step changes the index type
and reindexes the objects.
"""
def __call__(self):
index_name = 'foo'
if self.catalog_has_index(index_name):
self.catalog_remove_index(index_name)
self.catalog_add_index(index_name, 'KeywordIndex')
self.catalog_rebuild_index(index_name)
Registration in ``configure.zcml`` (assuming it's in the same directory):
.. code:: xml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
i18n_domain="my.package">
<genericsetup:upgradeStep
profile="my.package:default"
source="4"
destination="5"
title="Update index 'foo'."
handler=".upgrades.UpdateFooIndex"
/>
</configure>
Updating objects with progress logging
--------------------------------------
Since an upgrade step often updates a set of objects indexed in the catalog,
there is a useful helper method `self.objects()` which combines querying the
catalog with the `Progress Logger`_.
The catalog is queried unrestricted so that we handle all the objects.
Here is an example for updating all objects of a particular type:
.. code:: python
from ftw.upgrade import ProgressLogger
from ftw.upgrade import UpgradeStep
class ExcludeFilesFromNavigation(UpgradeStep):
def __call__(self):
for obj in self.objects({'portal_type': 'File'},
'Enable exclude from navigation for files'):
obj.setExcludeFromNav(True)
When running the upgrade step you'll be shown a progress log::
INFO ftw.upgrade STARTING Enable exclude from navigation for files
INFO ftw.upgrade 1 of 10 (10%): Enable exclude from navigation for files
INFO ftw.upgrade 5 of 50 (50%): Enable exclude from navigation for files
INFO ftw.upgrade 10 of 10 (100%): Enable exclude from navigation for files
INFO ftw.upgrade DONE: Enable exclude from navigation for files
Methods
-------
The ``UpgradeStep`` class has various helper functions:
``self.getToolByName(tool_name)``
Returns the tool with the name ``tool_name`` of the upgraded site.
``self.objects(catalog_query, message, logger=None, savepoints=None)``
Queries the catalog (unrestricted) and an iterator with full objects.
The iterator configures and calls a ``ProgressLogger`` with the
passed ``message``.
If set to a non-zero value, the ``savepoints`` argument causes a transaction
savepoint to be created every n items. This can be used to keep memory usage
in check when creating large transactions.
The default value ``None`` indicates that we are not configuring this feature
and it should use the default configuration, which is usually ``1000``. See
the `Savepoints`_ section for more details.
In order to disable savepoints completely, you can use ``savepoints=False``.
This method will remove matching brains from the catalog when they are broken
because the object of the brain no longer exists.
The progress logger will not compensate for the skipped objects and terminate
before reaching 100%.
``self.catalog_rebuild_index(name)``
Reindex the ``portal_catalog`` index identified by ``name``.
``self.catalog_reindex_objects(query, idxs=None, savepoints=None)``
Reindex all objects found in the catalog with `query`.
A list of indexes can be passed as `idxs` for limiting the
indexed indexes.
The ``savepoints`` argument will be passed to ``self.objects()``.
``self.catalog_has_index(name)``
Returns whether there is a catalog index ``name``.
``self.catalog_add_index(name, type_, extra=None)``
Adds a new index to the ``portal_catalog`` tool.
``self.catalog_remove_index(name)``
Removes an index from the ``portal_catalog`` tool.
``self.actions_remove_action(category, action_id)``
Removes an action identified by ``action_id`` within the given
``category`` from the ``portal_actions`` tool.
``self.catalog_unrestricted_get_object(brain)``
Returns the unrestricted object of a brain.
Dead brains, for which there is no longer an object, are removed from
the catalog and ``None`` is returned.
``self.catalog_unrestricted_search(query, full_objects=False)``
Searches the catalog without checking security.
When `full_objects` is `True`, unrestricted objects are
returned instead of brains.
Upgrade steps should generally use unrestricted catalog access
since all objects should be upgraded - even if the manager
running the upgrades has no access on the objects.
When using ``full_objects``, dead brains, for which there is no longer
an object, are removed from the catalog and skipped in the generator.
When dead brains are removed, the resulting sized generator's length
will not compensate for the skipped objects and therefore be too large.
``self.actions_add_type_action(self, portal_type, after, action_id, **kwargs)``
Add a ``portal_types`` action from the type identified
by ``portal_type``, the position can be defined by the
``after`` attribute. If the after action can not be found,
the action will be inserted at the end of the list.
``self.actions_remove_type_action(portal_type, action_id)``
Removes a ``portal_types`` action from the type identified
by ``portal_type`` with the action id ``action_id``.
``self.set_property(context, key, value, data_type='string')``
Safely set a property with the key ``key`` and the value ``value``
on the given ``context``.
The property is created with the type ``data_type`` if it does not exist.
``self.add_lines_to_property(context, key, lines)``
Updates a property with key ``key`` on the object ``context``
adding ``lines``.
The property is expected to be of type "lines".
If the property does not exist it is created.
``self.setup_install_profile(profileid, steps=None)``
Installs the generic setup profile identified by ``profileid``.
If a list step names is passed with ``steps`` (e.g. ['actions']),
only those steps are installed. All steps are installed by default.
``self.ensure_profile_installed(profileid)``
Install a generic setup profile only when it is not yet installed.
``self.install_upgrade_profile(steps=None)``
Installs the generic setup profile associated with this upgrade step.
The profile may be associated to upgrade steps by using either the
``upgrade-step:importProfile`` or the ``upgrade-step:directory`` directive.
``self.is_profile_installed(profileid)``
Checks whether a generic setup profile is installed.
Respects product uninstallation via quickinstaller.
``self.is_product_installed(product_name)``
Check whether a product is installed.
``self.uninstall_product(product_name)``
Uninstalls a product using the quick installer.
``self.migrate_class(obj, new_class)``
Changes the class of an object. It has a special handling for BTreeFolder2Base
based containers.
``self.remove_broken_browserlayer(name, dottedname)``
Removes a browser layer registration whose interface can't be imported any
more from the persistent registry.
Messages like these on instance boot time can be an indication of this
problem:
``WARNING OFS.Uninstalled Could not import class 'IMyProductSpecific' from
module 'my.product.interfaces'``
``self.update_security(obj, reindex_security=True)``
Update the security of a single object (checkboxes in manage_access).
This is usefuly in combination with the ``ProgressLogger``.
It is possible to skip reindexing the object security in the catalog
(``allowedRolesAndUsers``). This speeds up the update but should only be disabled
when there are no changes for the ``View`` permission.
``self.update_workflow_security(workflow_names, reindex_security=True, savepoints=None)``
Update all objects which have one of a list of workflows.
This is useful when updating a bunch of workflows and you want to make sure
that the object security is updated properly.
The update done is kept as small as possible by only searching for
types which might have this workflow. It does support placeful workflow policies.
To further speed this up you can pass ``reindex_security=False``, but you need to make
sure you did not change any security relevant permissions (only ``View`` needs
``reindex_security=True`` for default Plone).
By default, transaction savepoints are created every 1000th object. This prevents
exaggerated memory consumption when creating large transactions. If your server has
enough memory, you may turn savepoints off by passing ``savepoints=None``.
``self.base_profile``
The attribute ``base_profile`` contains the profile name of the upgraded
profile including the ``profile-`` prefix.
Example: ``u"profile-the.package:default"``.
This information is only available when using the
``upgrade-step:directory`` directive.
``self.target_version``
The attribute ``target_version`` contains the target version of the upgrade
step as a bytestring.
Example with upgrade step directory: ``"20110101000000"``.
This information is only available when using the
``upgrade-step:directory`` directive.
Progress logger
---------------
When an upgrade step is taking a long time to complete (e.g. while performing a data migration), the
administrator needs to have information about the progress of the update. It is also important to have
continuous output for avoiding proxy timeouts when accessing Zope through a webserver / proxy.
The ``ProgressLogger`` makes logging progress very easy:
.. code:: python
from ftw.upgrade import ProgressLogger
from ftw.upgrade import UpgradeStep
class MyUpgrade(UpgradeStep):
def __call__(self):
objects = self.catalog_unrestricted_search(
{'portal_type': 'MyType'}, full_objects=True)
for obj in ProgressLogger('Migrate my type', objects):
self.upgrade_obj(obj)
def upgrade_obj(self, obj):
do_something_with(obj)
The logger will log the current progress every 5 seconds (default).
Example log output::
INFO ftw.upgrade STARTING Migrate MyType
INFO ftw.upgrade 1 of 10 (10%): Migrate MyType
INFO ftw.upgrade 5 of 50 (50%): Migrate MyType
INFO ftw.upgrade 10 of 10 (100%): Migrate MyType
INFO ftw.upgrade DONE: Migrate MyType
Workflow Chain Updater
----------------------
When the workflow is changed for a content type, the workflow state is
reset to the init state of new workflow for every existing object of this
type. This can be really annoying.
The `WorkflowChainUpdater` takes care of setting every object to the correct
state after changing the chain (the workflow for the type):
.. code:: python
from ftw.upgrade.workflow import WorkflowChainUpdater
from ftw.upgrade import UpgradeStep
class UpdateWorkflowChains(UpgradeStep):
def __call__(self):
query = {'portal_type': ['Document', 'Folder']}
objects = self.catalog_unrestricted_search(
query, full_objects=True)
review_state_mapping={
('intranet_workflow', 'plone_workflow'): {
'external': 'published',
'pending': 'pending'}}
with WorkflowChainUpdater(objects, review_state_mapping):
# assume that the profile 1002 does install a new workflow
# chain for Document and Folder.
self.setup_install_profile('profile-my.package.upgrades:1002')
The workflow chain updater migrates the workflow history by default.
The workflow history migration can be disabled by setting
``migrate_workflow_history`` to ``False``:
.. code:: python
with WorkflowChainUpdater(objects, review_state_mapping,
migrate_workflow_history=False):
# code
If a transition mapping is provided, the actions in the workflow history
entries are migrated according to the mapping so that the translations
work for the new workflow:
.. code:: python
transition_mapping = {
('intranet_workflow', 'new_workflow'): {
'submit': 'submit-for-approval'}}
with WorkflowChainUpdater(objects, review_state_mapping,
transition_mapping=transition_mapping):
# code
Placeful Workflow Policy Activator
----------------------------------
When manually activating a placeful workflow policy all objects with a new
workflow might be reset to the initial state of the new workflow.
ftw.upgrade has a tool for enabling placeful workflow policies without
breaking the review state by mapping it from the old to the new workflows:
.. code:: python
from ftw.upgrade.placefulworkflow import PlacefulWorkflowPolicyActivator
from ftw.upgrade import UpgradeStep
class ActivatePlacefulWorkflowPolicy(UpgradeStep):
def __call__(self):
portal_url = self.getToolByName('portal_url')
portal = portal_url.getPortalObject()
context = portal.unrestrictedTraverse('path/to/object')
activator = PlacefulWorkflowPolicyActivator(context)
activator.activate_policy(
'local_policy',
review_state_mapping={
('intranet_workflow', 'plone_workflow'): {
'external': 'published',
'pending': 'pending'}})
The above example activates a placeful workflow policy recursively on the
object under "path/to/object", enabling the placeful workflow policy
"local_policy".
The mapping then maps the "intranet_workflow" to the "plone_workflow" by
defining which old states (key, intranet_workflow) should be changed to
the new states (value, plone_workflow).
**Options**
- `activate_in`: Activates the placeful workflow policy for the passed in
object (`True` by default).
- `activate_below`: Activates the placeful workflow policy for the children
of the passed in object, recursively (`True` by default).
- `update_security`: Update object security and reindex
allowedRolesAndUsers (`True` by default).
Inplace Migrator
----------------
The inplace migrator provides a fast and easy way for migrating content in
upgrade steps.
It can be used for example to migrate from Archetypes to Dexterity.
The difference between Plone's standard migration and the inplace migration
is that the standard migration creates a new sibling and moves the children
and the inplace migration simply replaces the objects within the tree and
attaches the children to the new parent.
This is a much faster approach since no move / rename events are fired.
Example usage:
.. code:: python
from ftw.upgrade import UpgradeStep
from ftw.upgrade.migration import InplaceMigrator
class MigrateContentPages(UpgradeStep):
def __call__(self):
self.install_upgrade_profile()
migrator = InplaceMigrator(
new_portal_type='DXContentPage',
field_mapping={'text': 'content'},
)
for obj in self.objects({'portal_type': 'ATContentPage'},
'Migrate content pages to dexterity'):
migrator.migrate_object(obj)
**Arguments:**
- ``new_portal_type`` (required): The portal_type name of the destination type.
- ``field_mapping``: A mapping of old fieldnames to new fieldnames.
- ``options``: One or many options (binary flags).
- ``ignore_fields``: A list of fields which should be ignored.
- ``attributes_to_migrate``: A list of attributes (not fields!) which should be
copied from the old to the new object. This defaults to
``DEFAULT_ATTRIBUTES_TO_COPY``.
**Options:**
The options are binary flags: multiple options can be or-ed.
Example:
.. code:: python
from ftw.upgrade.migration import IGNORE_STANDARD_FIELD_MAPPING
from ftw.upgrade.migration import IGNORE_UNMAPPED_FIELDS
from ftw.upgrade.migration import InplaceMigrator
migrator = InplaceMigrator(
'DXContentPage',
options=IGNORE_UNMAPPED_FIELDS | IGNORE_STANDARD_FIELD_MAPPING,
})
- ``DISABLE_FIELD_AUTOMAPPING``: by default, fields with the same name on the
old and the new implementation are automatically mapped. This flags disables
the automatic mapping.
- ``IGNORE_UNMAPPED_FIELDS``: by default, a ``FieldsNotMappedError`` is raised
when unmapped fields are detected. This flags disables this behavior and
unmapped fields are simply ignored.
- ``BACKUP_AND_IGNORE_UNMAPPED_FIELDS``: ignores unmapped fields but stores the
values of unmapped fields in the annotations of the new object (using the
key from the constant ``UNMAPPED_FIELDS_BACKUP_ANN_KEY``), so that the values
can be handled later. This is useful when having additional fields (schema
extender).
- ``IGNORE_STANDARD_FIELD_MAPPING`` by default, the ``STANDARD_FIELD_MAPPING``
is merged into each field mapping, containing standard Plone field mappings
from Archetypes to Dexterity. This flag disables this behavior.
- ``IGNORE_DEFAULT_IGNORE_FIELDS`` by default, the fields listed in
``DEFAULT_IGNORED_FIELDS`` are skipped. This flag disables this behavior.
- ``SKIP_MODIFIED_EVENT`` when `True`, no modified event is triggered.
Upgrade directories
===================
The ``upgrade-step:directory`` ZCML directive allows us to use a new upgrade step
definition syntax with these **advantages**:
- The directory is once registered (ZCML) and automatically scanned at Zope boot time.
This *reduces the ZCML* used for each upgrade step
and avoids the redundancy created by having to specify the profile version in multiple places.
- Timestamps are used instead of version numbers.
Because of that we have *less merge-conflicts*.
- The version in the profile's ``metadata.xml`` is removed and dynamically set
at Zope boot time to the version of the latest upgrade step.
We no longer have to maintain this version in upgrades.
- Each upgrade is automatically a Generic Setup profile.
An instance of the ``UpgradeStep`` class knows which profile it belongs to,
and that profile can easily be imported with ``self.install_upgrade_profile()``.
``self.install_upgrade_profile()``.
- The ``manage-upgrades`` view shows us when we have accidentally merged upgrade steps
with older timestamps than already executed upgrade steps.
This helps us detect a long-term-branch merge problem.
Setting up an upgrade directory
-------------------------------
- Register an upgrade directory for your profile (e.g. ``my/package/configure.zcml``):
.. code:: xml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:upgrade-step="http://namespaces.zope.org/ftw.upgrade"
i18n_domain="my.package">
<include package="ftw.upgrade" file="meta.zcml" />
<upgrade-step:directory
profile="my.package:default"
directory="./upgrades"
/>
</configure>
- Create the configured upgrade step directory (e.g. ``my/package/upgrades``) and put an
empty ``__init__.py`` in this directory (prevents some python import warnings).
- Remove the version from the ``metadata.xml`` of the profile for which this upgrade step
directory is configured (e.g. ``my/package/profiles/default/metadata.xml``):
.. code:: xml
<?xml version="1.0"?>
<metadata>
<dependencies>
<dependency>profile-other.package:default</dependency>
</dependencies>
</metadata>
Declare upgrades soft dependencies
----------------------------------
When having optional dependencies (``extras_require``), we sometimes need to tell
``ftw.upgrade`` that our optional dependency's upgrades needs to be installed
before our upgrades are installed.
We do that by declare a soft dependency in the ``upgrade-step:directory``
directive.
It is possible to declare multiple dependencies by separating them
with whitespace.
.. code:: xml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:upgrade-step="http://namespaces.zope.org/ftw.upgrade"
i18n_domain="my.package">
<include package="ftw.upgrade" file="meta.zcml" />
<upgrade-step:directory
profile="my.package:default"
directory="./upgrades"
soft_dependencies="other.package:default
collective.fancy:default"
/>
</configure>
Creating an upgrade step
------------------------
Upgrade steps can be generated with ``ftw.upgrade``'s ``bin/upgrade`` console script.
The idea is to install this script with buildout using
`zc.recipe.egg <https://pypi.org/project/zc.recipe.egg/>`_.
Once installed, upgrade steps can simply be scaffolded with the script:
.. code::
$ bin/upgrade create AddControlpanelAction
The ``create`` command searches for your ``upgrades`` directory by resolving the
``*.egg-info/top_level.txt`` file. If you have no egg-infos or your upgrades directory is
named differently the automatic discovery does not work and you can provide the
path to the upgrades directory using the ``--path`` argument.
.. sidebar:: Global create-upgrade script
The
`create-upgrade <https://github.com/4teamwork/ftw.upgrade/blob/master/scripts/create-upgrade>`_
script helps you create upgrade steps in any directory (also when not named ``upgrades``).
Download it and place it somewhere in your ``PATH``, cd into the directory and create an upgrade
step: ``create-upgrade add_control_panel_action``.
If you would like to have colorized output in the terminal, you can install
the ``colors`` extras (``ftw.upgrade[colors]``).
Reordering upgrade steps
------------------------
The ``bin/upgrade`` console script provides a ``touch`` for reordering generated upgrade steps.
With the optional arguments ``--before`` and ``--after`` upgrade steps can be moved to a specific
position.
When the optional arguments are omitted, the upgrade step timestamp is set to the current time.
Examples:
.. code::
$ bin/upgrade touch upgrades/20141218093045_add_controlpanel_action
$ bin/upgrade touch 20141218093045_add_controlpanel_action --before 20141220181500_update_registry
$ bin/upgrade touch 20141218093045_add_controlpanel_action --after 20141220181500_update_registry
Creating an upgrade step manually
---------------------------------
- Create a directory for the upgrade step in the upgrades directory.
The directory name must contain a timestamp and a description, concatenated by an underscore,
e.g. ``YYYYMMDDHHMMII_description_of_what_is_done``:
.. code::
$ mkdir my/package/upgrades/20141218093045_add_controlpanel_action
- Next, create the upgrade step code in an ``upgrade.py`` in the above directory.
This file needs to be created, otherwise the upgrade step is not registered.
.. code:: python
# my/package/upgrades/20141218093045_add_controlpanel_action/upgrade.py
from ftw.upgrade import UpgradeStep
class AddControlPanelAction(UpgradeStep):
"""Adds a new control panel action for the package.
"""
def __call__(self):
# maybe do something
self.install_upgrade_profile()
# maybe do something
..
- You must inherit from ``UpgradeStep``.
- Give your class a proper name, although it does not show up anywhere.
- Add a descriptive docstring to the class, the first consecutive lines are
used as upgrade step description.
- Do not forget to execute ``self.install_upgrade_profile()`` if you have Generic Setup based
changes in your upgrade.
- Put Generic Setup files in the same upgrade step directory, it automatically acts as a
Generic Setup profile just for this upgrade step.
The ``install_upgrade_profile`` knows what to import.
For our example this means we put a file at
``my/package/upgrades/20141218093045_add_controlpanel_action/controlpanel.xml``
which adds the new control panel action.
The resulting directory structure should be something like this:
.. code::
my/
package/
configure.zcml # registers the profile and the upgrade directory
upgrades/ # contains the upgrade steps
__init__.py # prevents python import warnings
20141218093045_add_controlpanel_action/ # our first upgrade step
upgrade.py # should contain an ``UpgradeStep`` subclass
controlpanel.xml # Generic Setup data to import
20141220181500_update_registry/ # another upgrade step
upgrade.py
*.xml
profiles/
default/ # the default Generic Setup profile
metadata.xml
Deferrable upgrades
-------------------
Deferrable upgrades are a special type of upgrade that can be omitted on
demand. They still will be proposed and installed by default but can be
excluded from installation by setting a flag.
Deferrable upgrades can be used to decouple upgrades that need not be run right
now, but only eventually, from the critical upgrade path. This can be
particularly useful for long running data migrations or for fix-scripts.
Upgrade-steps can be marked as deferrable by setting a class attribute
``deferrable`` on a subclass of ``UpgradeStep``:
.. code:: python
# my/package/upgrades/20180709135657_long_running_upgrade/upgrade.py
from ftw.upgrade import UpgradeStep
class LongRunningUpgrade(UpgradeStep):
"""Potentially long running upgrade which is deferrable.
"""
deferrable = True
def __call__(self):
pass
When you install upgrades from the command line, you can skip the installation
of deferred upgrade steps with:
.. code:: sh
$ bin/upgrade install -s plone --proposed --skip-deferrable
When you install upgrades with the ``@@manage-upgrades`` view, deferrable
upgrade steps show an additional icon and can be deselected manually.
JSON API
========
The JSON API allows to get profiles and upgrades for a Plone site and execute upgrades.
Authentication and authorization
--------------------------------
The API is available for users with the "cmf.ManagePortal" permission, usually the "Manager"
role is required.
Versioning
----------
A specific API version can be requested by adding the version to the URL. Example:
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/upgrades-api/v1/list_plone_sites
API Discovery
-------------
The API is discoverable and self descriptive.
The API description is returned when the API action is omitted:
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/upgrades-api/
{
"api_version": "v1",
"actions": [
{
"request_method": "GET",
"required_params": [],
"name": "current_user",
"description": "Return the current user when authenticated properly. This can be used for testing authentication."
},
{
"request_method": "GET",
"required_params": [],
"name": "list_plone_sites",
"description": "Returns a list of Plone sites."
}
]
}
$ curl -uadmin:admin http://localhost:8080/Plone/upgrades-api/
...
Listing Plone sites:
--------------------
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/upgrades-api/list_plone_sites
[
{
"path": "/Plone",
"id": "Plone",
"title": "Website"
}
]
Listing profiles and upgrades
-----------------------------
List all profiles
~~~~~~~~~~~~~~~~~
Listing all installed Generic Setup profiles with upgrades for a Plone site:
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/Plone/upgrades-api/list_profiles
[
{
"id": "Products.CMFEditions:CMFEditions",
"db_version": "4",
"product": "Products.CMFEditions",
"title": "CMFEditions",
"outdated_fs_version": false,
"fs_version": "4",
"upgrades": [
{
"proposed": false,
"title": "Fix portal_historyidhandler",
"outdated_fs_version": false,
"orphan": false,
"deferred": false,
"dest": "3",
"done": true,
"source": "2.0",
"id": "3@Products.CMFEditions:CMFEditions"
},
...
Get a profile
~~~~~~~~~~~~~
Listing a single profile and its upgrades:
.. code:: sh
$ curl -uadmin:admin "http://localhost:8080/Plone/upgrades-api/get_profile?profileid=Products.TinyMCE:TinyMCE"
{
"id": "Products.TinyMCE:TinyMCE",
"db_version": "7",
"product": "Products.TinyMCE",
"title": "TinyMCE Editor Support",
"outdated_fs_version": false,
"fs_version": "7",
"upgrades": [
{
"proposed": false,
"title": "Upgrade TinyMCE",
"outdated_fs_version": false,
"orphan": false,
"deferred": false,
"dest": "1.1",
"done": true,
"source": "1.0",
"id": "1.1@Products.TinyMCE:TinyMCE"
},
...
List proposed profiles
~~~~~~~~~~~~~~~~~~~~~~
Listing all profiles proposing upgrades, each profile only including upgrades which
are propsosed:
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/Plone/upgrades-api/list_profiles_proposing_upgrades
...
List proposed upgrades
~~~~~~~~~~~~~~~~~~~~~~
Listing all proposed upgrades without the wrapping profile infos:
.. code:: sh
$ curl -uadmin:admin http://localhost:8080/Plone/upgrades-api/list_proposed_upgrades
[
{
"proposed": true,
"title": "Foo.",
"outdated_fs_version": false,
"orphan": true,
"deferred": false,
"dest": "20150114104527",
"done": false,
"source": "10000000000000",
"id": "20150114104527@ftw.upgrade:default"
}
]
Executing upgrades
------------------
When executing upgrades the response is not of type JSON but a streamed upgrade log.
If the request is correct, the response status will always be 200 OK, no matter whether
the upgrades will install correctly or not.
If an upgrade fails, the request and the transaction is aborted and the response content
will end with "Result: FAILURE\n".
If the upgrade succeeds, the response content will end with "Result: SUCCESS\n".
Executing selected upgrades
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Selected upgrades can be executed by their API-ID (format: "<dest>@<profileid>").
When upgrade groups are used the API-ID is kind of ambiguous and identifies / installs all
upgrade steps of the same profile with the same target version.
All upgrade steps are reordered to the installation order proposed by ftw.upgrade.
It is not possible to change the order within one request, use multiple requests for
unproposed installation order.
The installation order is done by topogically ordering the profiles by their dependencies
and ordering the upgrades within each profile by their target version.
Example for executing a selected set of upgrades:
.. code:: sh
$ curl -uadmin:admin -X POST "http://localhost:8080/Plone/upgrades-api/execute_upgrades?upgrades:list=7@Products.TinyMCE:TinyMCE&upgrades:list=20150114104527@ftw.upgrade:default"
2015-01-14 11:16:14 INFO ftw.upgrade ______________________________________________________________________
2015-01-14 11:16:14 INFO ftw.upgrade UPGRADE STEP Products.TinyMCE:TinyMCE: Upgrade TinyMCE 1.3.4 to 1.3.5
2015-01-14 11:16:14 INFO ftw.upgrade Ran upgrade step Upgrade TinyMCE 1.3.4 to 1.3.5 for profile Products.TinyMCE:TinyMCE
2015-01-14 11:16:14 INFO ftw.upgrade Upgrade step duration: 1 second
2015-01-14 11:16:14 INFO ftw.upgrade ______________________________________________________________________
2015-01-14 11:16:14 INFO ftw.upgrade UPGRADE STEP ftw.upgrade:default: Foo.
2015-01-14 11:16:14 INFO GenericSetup.rolemap Role / permission map imported.
2015-01-14 11:16:14 INFO GenericSetup.archetypetool Archetype tool imported.
2015-01-14 11:16:14 INFO ftw.upgrade Ran upgrade step Foo. for profile ftw.upgrade:default
2015-01-14 11:16:14 INFO ftw.upgrade Upgrade step duration: 1 second
Result: SUCCESS
Execute all proposed upgrades
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example for executing all proposed upgrades of a Plone site:
.. code:: sh
$ curl -uadmin:admin -X POST http://localhost:8080/Plone/upgrades-api/execute_proposed_upgrades
2015-01-14 11:17:34 INFO ftw.upgrade ______________________________________________________________________
2015-01-14 11:17:34 INFO ftw.upgrade UPGRADE STEP ftw.upgrade:default: Bar.
2015-01-14 11:17:35 INFO GenericSetup.rolemap Role / permission map imported.
2015-01-14 11:17:35 INFO GenericSetup.archetypetool Archetype tool imported.
2015-01-14 11:17:35 INFO ftw.upgrade Ran upgrade step Bar. for profile ftw.upgrade:default
2015-01-14 11:17:35 INFO ftw.upgrade Upgrade step duration: 1 second
Result: SUCCESS
To commit after each upgrade, pass the ``intermediate_commit`` argument:
.. code:: sh
$ curl -uadmin:admin -X POST http://localhost:8080/Plone/upgrades-api/execute_proposed_upgrades?intermediate_commit=true
Installing profiles
~~~~~~~~~~~~~~~~~~~
You can install complete profiles. When the profile is already
installed, nothing is done. Usually you will want to install the
default profile, but it is fine to install an uninstall profile.
Note that we do nothing with the ``portal_quickinstaller``. So if you
install an uninstall profile, you may still see the product as
installed. But for default profiles everything works as you would
expect.
Example for installing PloneFormGen (which was not installed yet) and
ftw.upgrade (which was already installed):
.. code:: sh
$ curl -uadmin:admin -X POST "http://localhost:8080/Plone/upgrades-api/execute_profiles?profiles:list=Products.PloneFormGen:default&profiles:list=ftw.upgrade:default"
2016-01-05 13:09:46 INFO ftw.upgrade Installing profile Products.PloneFormGen:default.
2016-01-05 13:09:46 INFO GenericSetup.rolemap Role / permission map imported.
...
2016-01-05 13:09:48 INFO GenericSetup.types 'FieldsetEnd' type info imported.
2016-01-05 13:09:48 INFO GenericSetup.factorytool FactoryTool settings imported.
2016-01-05 13:09:48 INFO ftw.upgrade Done installing profile Products.PloneFormGen:default.
2016-01-05 13:09:48 INFO ftw.upgrade Ignoring already installed profile ftw.upgrade:default.
Result: SUCCESS
By default, already installed profiles are skipped.
When supplying the ``force_reinstall=True`` request parameter,
already installed profiles will be reinstalled.
Upgrading Plone
~~~~~~~~~~~~~~~
You can migrate your Plone Site. This is what you would manually do
in the @@plone-upgrade view, which is linked to in the overview
control panel (or the ZMI) when your Plone Site needs updating.
Example for upgrading Plone:
.. code:: sh
$ curl -uadmin:admin -X POST "http://localhost:8080/test/upgrades-api/plone_upgrade"
"Plone Site has been updated."
Example for upgrading Plone when no upgrade is needed:
.. code:: sh
$ curl -uadmin:admin -X POST "http://localhost:8080/test/upgrades-api/plone_upgrade"
"Plone Site was already up to date."
For checking whether a Plone upgrade is needed, you can do:
.. code:: sh
$ curl -uadmin:admin -X POST "http://localhost:8080/test/upgrades-api/plone_upgrade_needed"
Recook resources
----------------
CSS and JavaScript resource bundles can be recooked:
.. code:: sh
$ curl -uadmin:admin -X POST http://localhost:8080/Plone/upgrades-api/recook_resources
"OK"
Combine bundles
---------------
CSS and JavaScript bundles can be combined:
.. code:: sh
$ curl -uadmin:admin -X POST http://localhost:8080/Plone/upgrades-api/combine_bundles
"OK"
This is for Plone 5 or higher.
This runs the same code that runs when you import a profile that makes changes in the resource registries.
Import-Profile Upgrade Steps
============================
Sometimes an upgrade step consists solely of importing a purpose-made generic setup
profile. Creating such upgrade steps are often much simpler than doing
the change in python, because we can simply copy the necessary parts of the new
default generic setup profile into the upgrade step profile.
Normally to do this, we would have to register an upgrade step and a Generic Setup
profile and write an upgrade step handler importing the profile.
ftw.upgrade makes this much simpler by providing an ``importProfile`` ZCML directive
specifically for this use case.
Example ``configure.zcml`` meant to be placed in your ``upgrades`` sub-package:
.. code:: xml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:upgrade-step="http://namespaces.zope.org/ftw.upgrade"
i18n_domain="my.package">
<include package="ftw.upgrade" file="meta.zcml" />
<upgrade-step:importProfile
title="Update email_from_address"
profile="my.package:default"
source="1007"
destination="1008"
directory="profiles/1008"
/>
</configure>
This example upgrade step updates the ``email_from_address`` property.
A generic setup profile is automatically registered and hooked up with the
generated upgrade step handler.
Simply put a ``properties.xml`` in the folder ``profiles/1008`` relative to the
above ``configure.zcml`` and the upgrade step is ready for deployment.
Optionally, a ``handler`` may be defined.
The handler, a subclass of ``UpgradeStep``, can import the associated generic
setup profile with ``self.install_upgrade_profile()``.
IPostUpgrade adapter
====================
By registering an ``IPostUpgrade`` adapter it is possible to run custom code
after running upgrades.
All adapters are executed after each time upgrades were run, regardless of
which upgrades are run.
The name of the adapters should be the profile of the package, so that
``ftw.upgrade`` is able to execute the adapters in order of the GS dependencies.
Example adapter:
.. code:: python
from ftw.upgrade.interfaces import IPostUpgrade
from zope.interface import implements
class MyPostUpgradeAdapter(object):
implements(IPostUpgrade)
def __init__(self, portal, request):
self.portal = portal
self.request = request
def __call__(self):
# custom code, e.g. import a generic setup profile for customizations
Registration in ZCML:
.. code:: xml
<configure xmlns="http://namespaces.zope.org/zope">
<adapter
factory=".adapters.MyPostUpgradeAdapter"
provides="ftw.upgrade.interfaces.IPostUpgrade"
for="Products.CMFPlone.interfaces.siteroot.IPloneSiteRoot
zope.interface.Interface"
name="my.package:default" />
</configure>
Savepoints
==========
Certain iterators of ``ftw.upgrade`` are wrapped with a ``SavepointIterator``,
creating savepoints after each batch of items.
This allows us to keep the memory footprint low.
The threshold for the savepoint iterator can be passed to certain methods, such as
``self.objects`` in an upgrade, or it can be configured globally with an environment variable:
.. code::
UPGRADE_SAVEPOINT_THRESHOLD = 1000
The default savepoint threshold is 1000.
Memory optimization while running upgrades
==========================================
Zope is optimized for executing many smaller requests.
The ZODB pickle cache keeps objects in the memory, so that they can be used for the next
request.
Running a large upgrade is a long-running request though, increasing the chance of a
memory problem.
``ftw.upgrade`` tries to optimize the memory usage by creating savepoints and triggering
the pickle cache garbage collector.
In order for this to work properly you should configure your ZODB cache sizes correctly
(`zodb-cache-size-bytes` or `zodb-cache-size`).
Prevent ftw.upgrade from marking upgrades as installed
======================================================
``ftw.upgrade`` automatically marks all upgrade steps of a profile as installed when
the full profile is imported. This is important for the initial installation.
In certain situations you may want to import the profile but not mark the upgrade steps
as installed. For example this could be done in a big migration project where the default
migration path cannot be followed.
You can do that like this for all generic setup profiles:
.. code:: python
from ftw.upgrade.directory.subscribers import no_upgrade_step_marking
with no_upgrade_step_marking():
# install profile with portal_setup
or for certain generic setup profiles:
.. code:: python
from ftw.upgrade.directory.subscribers import no_upgrade_step_marking
with no_upgrade_step_marking('my.package:default'):
# install profile with portal_setup
Links
=====
- Github: https://github.com/4teamwork/ftw.upgrade
- Issues: https://github.com/4teamwork/ftw.upgrade/issues
- Pypi: https://pypi.org/project/ftw.upgrade/
- Continuous integration: https://jenkins.4teamwork.ch/search?q=ftw.upgrade
Copyright
=========
This package is copyright by `4teamwork <http://www.4teamwork.ch/>`_.
``ftw.upgrade`` is licensed under GNU General Public License, version 2.
Changelog
=========
3.3.1 (2022-07-08)
------------------
- Support dead brains in WorkflowSecurityUpdater. [njohner]
3.3.0 (2022-03-28)
------------------
- Allow choosing a specific instance to run upgrade commands. [njohner]
3.2.0 (2022-01-31)
------------------
- Log memory usage during upgrade steps. [njohner]
- Write upgrade step durations to a file. [njohner]
- Sweep cache during upgrade if memory is critical. [njohner]
3.1.1 (2021-09-07)
------------------
- Add method to iterate over brains in upgrade step. [njohner]
3.1.0 (2021-06-21)
------------------
- Add intermediate commit option to commit the transaction after each installed upgrade. [deiferni]
3.0.4 (2021-01-21)
------------------
- Do not call ``cookResources`` on dummy old resource registry tools. [maurits]
- When using Python3, use importlib instead of the deprecated imp module
to look for upgrade steps.
This removes the warning displayed about unclosed resources.
Fixes `issue 211 <https://github.com/4teamwork/ftw.upgrade/issues/211>`.
[ale-rt]
3.0.3 (2020-10-10)
------------------
- Do not depend anymore on argparse because it is already included in
Python 2.7 and in Python 3 since version 3.2
Fixes `issue 209 <https://github.com/4teamwork/ftw.upgrade/issues/209>`.
[ale-rt]
3.0.2 (2020-08-27)
------------------
- Properly compute ``find_start_version`` when the profile has combined
upgrade steps
Fixes `issue 207 <https://github.com/4teamwork/ftw.upgrade/issues/207>`. [ale-rt]
- Check for six.binary_type to avoid AttributeErrors when running under Python3.
[erral]
3.0.1 (2020-06-09)
------------------
- This Plone add-on now requires six >= 1.12.0. [mbaechtold]
- Instance port number discovery in ``wsgi.ini`` works also when the fast listen
option is choosen.
Fixes `issue 200 <https://github.com/4teamwork/ftw.upgrade/issues/200>`. [ale-rt]
- The plone_upgrade subcommand does not break on Python3
Fixes `issue 202 <https://github.com/4teamwork/ftw.upgrade/issues/202>`. [ale-rt]
- Remove a bunch of deprecation warnings
Fixes `issue 204 <https://github.com/4teamwork/ftw.upgrade/issues/204>`. [ale-rt]
3.0.0 (2020-03-23)
------------------
- Add support for Plone 5.2 and Python 3. [buchi]
- Also look for the instance port number in ``wsgi.ini``. [maurits]
2.16.0 (2020-02-14)
-------------------
- Allow additional indexes to be reindexed in the WorkflowChainUpdater. [tinagerber]
2.15.2 (2020-01-27)
-------------------
- Fix missing values in IntIds catalog as we go within migrate_intid(). [djowett-ftw]
2.15.1 (2019-12-16)
-------------------
- Cleanup broken catalog brains on `NotFound`. [jone]
2.15.0 (2019-12-12)
-------------------
- Add context manager for disabling upgrade step marking. [jone]
- Do not mark upgrade steps as installed when not doing a full import. [jone]
2.14.1 (2019-11-08)
-------------------
- Migrate creators even when dublin core behaviors are not enabled. [jone]
- Migrate empty values in RichTextFields correctly.
Fixes `https://github.com/4teamwork/izug.refegovservice/issues/2`. [djowett-ftw]
2.14.0 (2019-10-31)
-------------------
- Added ``--allow-outdated`` option to ``install`` command.
This allows installing upgrades or profiles on a not up-to-date site.
Fixes `issue 182 <https://github.com/4teamwork/ftw.upgrade/issues/182>`. [maurits]
2.13.0 (2019-08-22)
-------------------
- Added combine_bundles command for Plone 5.
This combines JS/CSS bundles together. [maurits]
2.12.2 (2019-06-19)
-------------------
- Make sure to always use a portal_migration tool wrapped in a RequestContainer.
(Fixes "AttributeError: REQUEST" on a Plone 5.1.x upgrade) [lgraf]
2.12.1 (2019-06-18)
-------------------
- Choose actual port used by ZServer layer to run CommandAndInstance tests against. [lgraf]
- Disable Diazo on upgrades-plain for Plone 5.1.5 support. [jone]
2.12.0 (2018-07-26)
-------------------
- Allow marking upgrades as deferred so they won't be proposed by default. [deiferni]
2.11.1 (2018-04-05)
-------------------
- Fix connection problem when zope.conf contains ip-address. [jone]
- Make sure remove_broken_browserlayer() helper doesn't fail if the browser
layer registration to be removed doesn't exist (any more). [lgraf]
2.11.0 (2018-01-31)
-------------------
- Provide upgrade step handler interfaces and handler class in wrapper. [jone]
- Do not propose executed upgrades newer than current db version. [jone]
2.10.0 (2018-01-08)
-------------------
- Support installing proposed upgrades of specific Generic Setup profiles.
Use ``bin/upgrade install --proposed the.package:default``. [jone]
2.9.0 (2017-12-14)
------------------
- Optimize memory footprint after every upgrade step. [jone]
- Reduce memory footprint in SavepointIterator by garbage-collecting connection cache. [jone]
- Set the default savepoint threshold to 1000; make it configurable. [jone]
- Enable savepoint iterator by default. Affects ``self.objects``. [jone]
- Use a SavepointIterator in the WorkflowSecurityUpdater in order not to exceed
memory. [mbaechtold]
2.8.1 (2017-10-13)
------------------
- Also catch AttributeErrors when accessing objects of broken brains. [buchi]
2.8.0 (2017-07-27)
------------------
- The upgrade step methods will remove and skip broken catalog brains. [jone]
2.7.2 (2017-07-13)
------------------
- Fix encoding issues in ASCII terminals. [jone]
2.7.1 (2017-06-28)
------------------
- Fix tempfile authentication when created by different user. [jone]
2.7.0 (2017-06-28)
------------------
- Support using ``bin/upgrade`` by another user than the Zope server
with less strict security checks.[jone]
2.6.1 (2017-06-28)
------------------
- Fix a bug which caused ``bin/upgrade`` to fail when the ``var`` directory
had the setguid flag active. [jone]
2.6.0 (2017-06-08)
------------------
- Log (re/un)-indexing progress if collective.indexing is installed. [deiferni]
2.5.0 (2017-06-07)
------------------
- Add support for Plone 5.1. [jone]
2.4.0 (2017-06-07)
------------------
- Escape < and > in browser logger. [lknoepfel]
- Log current item in ProcessLogger if logger exits unexpectedly. [lknoepfel]
2.3.1 (2017-02-15)
------------------
- Fix bug causing that versions are not properly set after upgrading
when switching versioning system. [jone]
- Avoid overriding customizations by reinstalling already installed
profiles while upgrading (Plone>=4.3.8). [jone]
2.3.0 (2017-02-14)
------------------
- InplaceMigrator: Preserve object position in parent. [lknoepfel]
- Do not downgrade installed version when installing an orphan upgrade step. [jone]
- Add "soft_dependencies" option to "upgrade-step:directory" directive. [jone]
2.2.0 (2017-01-30)
------------------
- Add method to remove a previously uninstalled portlet manager from the
persistent registry.
[deiferni]
2.1.1 (2016-12-13)
------------------
- Fix support for GS import by tarball upload. [jone]
2.1.0 (2016-12-06)
------------------
- Add upgrade step method ``ensure_profile_installed(profileid)``. [jone]
- Add upgrade step method ``is_profile_installed(profileid)``. [jone]
- Add upgrade step method ``is_product_installed(product_name)``. [jone]
2.0.5 (2016-10-24)
------------------
- Migration: fix error when file obj is an empty string. [jone]
2.0.4 (2016-10-24)
------------------
- Migration: do not migrate empty blobs. [jone]
2.0.3 (2016-09-27)
------------------
- Migration: support all types of standard relation fields. [jone]
2.0.2 (2016-09-27)
------------------
- Migration: skip invalid relations. [jone]
2.0.1 (2016-09-02)
------------------
- Added support for jQuery 1.9+ on @@manage-upgrades control panel. [neilferreira]
2.0.0 (2016-08-18)
------------------
- Fix NoneType AttributeError with newest requests module. [jone]
- Drop Plone 4.1 and 4.2 support. [jone]
- Implement inplace migrator. [jone]
1.19.0 (2016-04-11)
-------------------
- Add option to force reinstall already installed profiles. [jone]
1.18.1 (2016-03-09)
-------------------
- Disable automatic CSRF protection for authorized jsonapi requests. [jone]
1.18.0 (2016-02-16)
-------------------
- Provide the attributes ``base_profile`` and ``target_version`` on
upgrade steps when using the ``upgrade-step:directory`` directive. [jone]
- Fix profile version when using `upgrade-step:directory` and
having old upgrade steps but no new ones. [jone]
1.17.0 (2016-01-22)
-------------------
- Add ``bin/upgrade plone_upgrade_needed`` command. [jone]
1.16.3 (2016-01-22)
-------------------
- Fix upgrade scaffolding when having dots or other
non-alphanumeric characters. [jone]
1.16.2 (2016-01-15)
-------------------
- Actually the same as 1.16.1, but pypi was broken when I
released it and now it does not let me use the same version
number. :-(
[jone]
1.16.1 (2016-01-13)
-------------------
- Added documentation for the additions of the previous release. [maurits]
1.16.0 (2016-01-05)
-------------------
- Added ``--all-sites`` option. This iterates over all sites and
performs the specified command on each of them. A failing command
for one site will stop the entire command. [maurits]
- Configure logging for the command line utility. By default print
only our own logging, on info level or higher. With the new
``--verbose`` option print all loggers (so also from other packages
like ``requests``) at debug level and higher. [maurits]
- Added ``plone_upgrade`` command to upgrade a Plone Site. This is
what you would manually do in the ``@@plone-upgrade`` view. [maurits]
- Added support for installing profiles. Profiles are only applied
once. Example command line: ``bin/upgrade install --site Plone
--profiles Products.PloneFormGen:default``. [maurits]
- Prevented UnicodeEncodeError when piping output of ``bin/upgrade
sites``. This would fail when a site had non-ascii characters in
its title. [maurits]
1.15.1 (2015-11-11)
-------------------
- Change instance detection to support any name.
Before only "instance*" was supported.
[jone]
1.15.0 (2015-10-30)
-------------------
- Make "blessed" dependency optional in the "colors" extras.
[jone]
- Update references to class-migrated objects in the intid utility.
[deiferni]
1.14.8 (2015-09-21)
-------------------
- Migrate workflow states with wfhistory migration and do not set state manually unless necessary.
[tschanzt]
1.14.7 (2015-08-27)
-------------------
- Add an afterCommitHook that notifies about the transaction having been
committed (or aborted) after installing upgrades.
[lgraf]
- Fix authentication problem with bin/upgrade command.
[jone]
1.14.6 (2015-07-22)
-------------------
- Return context manager to allow "as" statements.
[lknoepfel]
1.14.5 (2015-05-20)
-------------------
- Update quickinstaller product version when upgrading a package.
[jone]
1.14.4 (2015-04-09)
-------------------
- Fix post upgrade ordering which was broken since 1.11.0.
[jone]
1.14.3 (2015-03-29)
-------------------
- Fix error in upgrade-step:directory directive.
The error occured when the directory was a subdirectory relative to the
ZCML directory, causing the package module to be replaced with the
upgrades package directory in sys.modules.
[jone]
- Fix issue with transaction note length when a large not already exists.
When the transaction note already has maximum length (e.g. with Archetypes notes),
nothing more should be added.
Also increased the threshold back (reduced in 1.14.2).
[jone]
1.14.2 (2015-03-25)
-------------------
- Reduce maximum transaction note length used by ftw.upgrade.
[jone]
1.14.1 (2015-03-18)
-------------------
- Command: fix instance discover when bound to public interface.
[jone]
1.14.0 (2015-02-24)
-------------------
- Command: add fake terminal fallback when blessed cannot be loaded.
This can happen for example when Python is built without curses support.
[jone]
- ``bin/upgrade recook`` command for recooking resources.
[jone]
- Recook resources after installing upgrades.
[jone]
- plone.reload support for upgrade step directory.
[jone]
1.13.0 (2015-02-20)
-------------------
- ``bin/upgrade``: automatically authenticate with a tempfile
negotiation mechanism when no other authentication information is
provided.
[jone]
- New ``bin/upgrade user`` command for testing authentication.
[jone]
1.12.0 (2015-02-16)
-------------------
- Add ``bin/upgrade`` commands ``sites``, ``list`` and ``install``.
This makes it possible to install upgrades from the console.
[jone]
- Update upgrade step scaffold to support plone.reload.
[jone]
- New JSON API implemented, accessible with `/upgrades-api`.
[jone]
- Executioner: `install_upgrades_by_api_ids` was added, allowing to install
a selection of upgrades identified by API ugprade ids.
[jone]
- Gatherer: `get_upgrades_by_api_ids` was added, returning upgrade infos
for a selection of API upgrade ids.
[jone]
- Gatherer: `get_upgrades` is deprecated and replaced by `get_profiles`.
`get_profiles` now has a `proposed_only` flag.
[jone]
1.11.0 (2015-01-08)
-------------------
- Reverse post upgrade adapter ordering.
The order was reversed, it should execute dependencies first.
[jone]
- create-upgrade: Make sure to quote argument passed to bin/upgrade.
[lgraf]
- Add a ``create-upgrade`` script which can be installed globally.
[jone]
- Create a ``bin/upgrade`` script:
- the ``create`` command creates a upgrade step in the "upgrades" directory.
- the ``touch`` command can be used for reordering upgrade steps.
[jone]
- New ``upgrade-step:directory`` directive for registering a directory
with upgrade steps which are automatically detected and registered.
[jone]
- Extend the importProfile directive so that a handler can be
defined. The handler may import the associated upgrade step
profile with the new method ``self.install_upgrade_profile()``.
[jone]
1.10.2 (2014-11-19)
-------------------
- Exclude uninstalled products from upgrades view.
[jone]
- Make upgrades appear in undo form again.
The transaction note fix in 1.7.4 caused upgrade transaction to not appear in the undo form.
[jone]
1.10.1 (2014-10-27)
-------------------
- Update upgrade view ordering for root nodes.
The dependency graph does not define any order for root
profiles (e.g. included in buildout directly), which causes
random sorting in the upgrade view for those profiles.
This change sorts those root profiles by name without changing
the order of profiles which is depended on.
[jone]
1.10.0 (2014-08-28)
-------------------
- Wrap step.objects in a SavepointIterator that creates a savepoint every n items.
[lgraf]
1.9.0 (2014-08-27)
------------------
- Add @@manage-upgrades-plain fallback view for @@manage-upgrades.
It does not include plone`s main template and thus might be able to render when
the default view fails for some reason.
[deiferni]
1.8.0 (2014-08-11)
------------------
- Prevent portal_quickinstaller from picking upgrade-steps instead of the
default-profile by prefixing the profile-id with ``upgrade_to_`` (fix #45)
[pbauer]
- Flag profiles whose filesystem version is outdated.
Highlights profiles with upgrades that lead to a destination version that is
higher than the corresponding profile's current filesystem version.
This usually means someone forgot to update the version in metadata.xml of the
corresponding profile.
[lgraf]
1.7.4 (2014-05-12)
------------------
- Extend workflow updater to migrate workflow history.
[jone]
- Fix workflow updater to always update objects.
The objects are updated even when it seems that the object was
not update or has no longer a workflow.
This fixes issues when updating a workflow, in which case the
old workflow and the new workflow has the same ID.
[jone]
- Make sure the transaction note does not get too long.
Zope limits the transaction note length. By actively managing the transaction note
we can provide fallbacks for when it gets too long because a lot of upgrade steps
are installed at the same time.
[jone]
1.7.3 (2014-04-30)
------------------
- Add ``uninstall_product`` method to upgrade step class.
[jone]
1.7.2 (2014-02-28)
------------------
- Update provided interfaces when migrating objects to new class.
[jone]
1.7.1 (2014-01-09)
------------------
- Fix LocationError on manage-ugprades view on cyclic dependencies.
[jone]
1.7.0 (2013-09-24)
------------------
- Add a ``update_workflow_security`` helper function to the upgrade step.
[jone]
1.6.0 (2013-08-30)
------------------
- Fix inplace modification bug when updating the catalog while
iterating over a catalog result.
[jone]
- Implement new ``importProfile`` directive for creating upgrade steps
that just import a specific upgrade step generic setup profile.
[jone]
1.5 (2013-08-16)
----------------
- Add a ``WorkflowChainUpdater`` for changing workflow chains without
resetting existing objects to the initial review state of the new
workflow.
[jone]
1.4.0 (2013-07-18)
------------------
- Added helper for adding a type_action.
[phgross]
- Add `objects` method to `UpgradeStep` for easy querying the catalog
and doing stuff with progress logging combined.
[jone]
- Make ProgressLogger an iterator too, because it is easier to use.
[jone]
- Improve logging while installing upgrade steps.
Show duration for installing.
[jone]
- Fix upgrade step icons for Plone 4.3.
[jone]
- Add ``update_security`` helper.
[jone]
- Fix incomplete status info entry prodcued by
placeful workflow policy activator.
[jone]
1.3 (2013-06-13)
----------------
- Implement a placeful workflow policy activator.
[jone]
- Added remove_broken_browserlayer method to step class.
[lgraf]
1.2.1 (2013-04-23)
------------------
- Keep modification date on reindexObject wihtout idxs.
[mathias.leimgruber]
1.2 (2013-01-24)
----------------
- onegov.ch approved: add badge to readme.
[jone]
- Remove 'step' and 'for' values from internal data structure.
This is needed for allowing us to serialize the data (json).
[jone]
- Add IPostUpgrade adapter hook.
[jone]
- Refactor dependency sorting into seperate function.
[jone]
- Add security declarations.
[jone]
- Fix wrong tool usage when installing a profile in step class.
[jone]
1.1 (2012-10-08)
----------------
- Add catalog_unrestricted_get_object and catalog_unrestricted_search methods to step class.
[jone]
- Handle profiles of packages which were removed but have leftover generic setup entries.
[jone]
1.0 (2012-08-13)
----------------
- Add installed upgrades to transaction note. Closes #7
[jone]
- Add ``migrate_class`` helper with _p_changed implementation supporting BTreeFolder2Base containers.
[jone]
- Remove ``purge_resource_registries()`` helper because it does not behave as expected.
[jone]
- Set min-height of upgrade output frame to 500px.
[jone]
- Print exceptions to browser log stream.
[jone]
1.0b2 (2012-07-04)
------------------
- Fix the upgrade registration problem (using a classmethod does not work
since registration fails).
[jone]
- Let @@manage-upgrade be usable without actually installing the GS profile.
[maethu]
1.0b1 (2012-06-27)
------------------
- First implementation.
[jone]