- I am app developer, We are having the server and cloud app for HTML but in cloud due to conflict with the native App we are requested to change the macro name to html-bobswift.
- In order to support for our server customers on the migration front we need to change our macro name in server where it is html to html-bobswift and we need to keep the existing pages to work.
- Please guide us better solution for our requirement and let me know if you need any additional details to support this.
Hi,
We faced a similar issue with one of our plugins.
You would need to run some SQL queries to update the macro name in the database.
If you want a reference, Our SQL file is available on this FAQ page.
Feel free to let me know if you need any help.
Regards,
John
Thanks John for the suggestion and inputs.
I think with this approach existing pages on the server will not work as we are changing the storage format through DB.
We are looking at the Customisation of the Listener which needs to trigger while the Migration Assistant kick start and existing pages should work as is in the server front after the migration as well as the migration is might happen at multiple times.
Few references we are looking are :
-
Use the Confluence Cloud Migration Assistant to migrate | Atlassian Support
Using: atlassian-app-cloud-migration dependancy - Reference from Atlassian as sample: Bitbucket
We were made some progress with second option but not through plugin upgrade listener. But through manual intervention in the configuration screen.
So, now we are looking at the option:1 how we can trigger only at the migration time and the previous pages should work as is.
Thanks
RK
The existing pages will work if you update the server instance with a custom build of the plugin with the cloud macro name and then migrate the instance to cloud.
I am not clear what is mean by custom build of the plugin ?
An unreleased & modified version of the plugin where the macro name is changed to the cloud macro name.
It can be installed by uploading the jar file.
Hi @ramakrishna,
The plugin listener isn’t really designed to post-process pages because it’s designed to provide you with a mechanism to upload any specific data to your service, e.g. global configuration.
One option is an upgrade task on the plugin to change the storage format, however this will generate a page edit and entry in history for each page.
If you modify the bodycontent
table directly the end user won’t have any auditing of the change.
Otherwise, I think you’re looking at providing a button to allow the admin to start the upgrade themselves, which would have the same effect as the upgrade task, I’d expect.
Please understand that the App Migration code at this time is at Proof of Concept, and not production level. The APIs may change, so if you need a solution now, please continue to look at the upgrade or manual task.
James.
We have come up with the following approach for now to address the issue of what we are having.
-
We designed a UI page on the Global configuration page which will list the page and templates with “html” macro in the server instance and also the count of the number of pages.
-
We are using HibernateContentQueryFactory to will pull the html macro details in the instance and the same is being used for templates
public class HtmlContentQueryFactory implements HibernateContentQueryFactory {
@Override
public Query getQuery(Session session, Object... parameters) throws HibernateException {
return session.createQuery("SELECT ceo FROM ContentEntityObject ceo, BodyContent bc "
+ "WHERE bc.bodyType = com.atlassian.confluence.core.BodyType.XHTML AND ceo.originalVersion is null AND ceo.title is not null AND (bc.body LIKE '%ac:name=\"html\"%' OR bc.body LIKE '%ac:name=%{html}%{html}%' OR bc.body LIKE '%ac:name=%{html:%}%') AND ceo = bc.content");
}
}
- Now we have the details in hand with the number of pages and templates with the macro in the instance we have an Action class for which will get the request from the Jquery configuration screen submit button to start the migration.
- In the business layer at the backend we use the following to make use of the hibernate results to be migrated.
List<ContentEntityObject> entities = ImmutableList.copyOf(findContentWithHtmlMacro());
// Hibernate query to get html macro pages
private Iterator<ContentEntityObject> findContentWithHtmlMacro() throws InvalidSearchException {
return contentManager.findByQuery(new ContentQuery<ContentEntityObject>("html.findAllHtmlInContents"), 0, Integer.MAX_VALUE);
}
- Will go over the results and used the following reference from Atlassian to update the pages and templates.
/**
* This method is used to update the page storage format with the newly given parameter values.
*
* @param newEntity
* @param originalEntity
*/
private void doMigrateContent(ContentEntityObject newEntity, ContentEntityObject originalEntity) throws Exception {
// make sure the new version is a second later than the pre-migrated version
// to ensure assumptions made by Page version comparators continue to be true.
final Date originalLastModificationDate = originalEntity.getLastModificationDate();
if (originalLastModificationDate != null) {
newEntity.setLastModificationDate(new Date(originalLastModificationDate.getTime() + 1000));
}
newEntity.setLastModifier(AuthenticatedUserThreadLocal.get());
newEntity.setVersionComment(Constants.MIGRATON_PAGE_UPDATE_MSG);
// If we are saving a draft we will need to update the version of the page the
// draft applies to (without this it would point to the wiki version which
// would be problematic
if (newEntity instanceof Draft) {
final Draft draft = (Draft) newEntity;
draft.setPageVersion(draft.getPageVersion() + 1);
}
@SuppressWarnings("deprecation")
SaveContext saveContext = new DefaultSaveContext(true, true, true);
// Various content types like Drafts, Comments, GlobalDescription, UserStatus, etc
// implement Versioned even though we don't actually support multiple versions
// of these types.Only save Pages and Blogs as versioned objects.
if ((newEntity instanceof Page) || (newEntity instanceof BlogPost)) {
contentManager.saveContentEntity(newEntity, originalEntity, saveContext);
} else {
contentManager.saveContentEntity(newEntity, saveContext);
}
}
For templates:
final PageTemplate original = (PageTemplate) pageTemplate.clone();
pageTemplate.setContent(migrationResult.getContent());
pageTemplateManager.savePageTemplate(pageTemplate, original);
After the completion of updating pages and template we used the Atlassian provided “Cloud Migration Assistant” tool to move the spaces to the target cloud instance. For now we are migrating all the spaces in the instances at one go. But while migrating to the cloud user have an option to chose only specific spaces can be migrated.
Feel free to reach out to me if anything is not clear.
We also left the old macro name available for those that didn’t need the migration so existing pages continue to work.
Hi @jrichards , does that mean that the migration API can’t be used to process/migrate macro parameters?
Yes that’s right. You should either pre-process them in an upgrade task in the onPrem instance, or process them after migration by polling the REST endpoints for the containers and also the updated ids so you can make the changes.
James.
I am also thinking about a different solution, which would be to “copy” the existing macro definitions in the cloud app, and change their names; this would duplicate the affected macros in the cloud app (though, their names could be “Macro X (migrated)” or something). The UI and handlers for the macros would be the same as for existing macros in the cloud app. A small change would need to be done to the macro parameters because the onPrem macros also have slightly different parameters.
To me, it seems like this would be better than processing and converting all of the macros in the onPrem instance. During my tests, the macro is present in the migrated page but there is no macro definition for it. As soon as I change the macro name in the onPrem app, and redo the migration, the macro sort of appears (though not as expected because of the difference in parameters).
So to me doing it the other way around should be easier, especially because running a long-running task that converts pages in the onPrem instance and replaces not only the macro name but also the relatively complex data structure is slightly risky and error-prone.
We are still mulling it over, though. Duplicating macro definitions in the cloud app might seem ugly to some.