Skip to content

Commit 3e95715

Browse files
authored
Added automatic project migration capabilities. Closes #1150 (#1157)
* WIP #1150 updated lib update fns * WIP #1150 renamed CheckLibraries -> CheckUpdates * WIP #1150 renamed file * WIP #1150 added update detection * WIP #1150 added ApplyUpdates plugin * WIP #1150 updated projeck update detection * WIP #1150 improved the commit message for the plugin * WIP #1150 working on ApplyUpdates test * WIP #1150 added helper method to Updates * WIP #1150 nop if no updates to apply * WIP #1150 updated tests * WIP fixed linting issue
1 parent 9177815 commit 3e95715

11 files changed

Lines changed: 528 additions & 217 deletions

File tree

src/common/updates/Updates.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* globals define */
2+
define([
3+
'q'
4+
], function(
5+
Q
6+
) {
7+
8+
const allUpdates = [
9+
{
10+
name: 'CustomUtilities',
11+
isNeeded: function(core, rootNode) {
12+
// Check the root directory for a MyUtilities node
13+
return core.loadChildren(rootNode)
14+
.then(children => {
15+
const names = children.map(node => core.getAttribute(node, 'name'));
16+
return !names.includes('MyUtilities');
17+
});
18+
},
19+
apply: function(core, rootNode, META) {
20+
// Create 'MyUtilities' node
21+
const utils = core.createNode({
22+
parent: rootNode,
23+
base: META.FCO
24+
});
25+
core.setAttribute(utils, 'name', 'MyUtilities');
26+
27+
// Add 'MyUtilities' to the META
28+
const META_ASPECT_SET_NAME = 'MetaAspectSet';
29+
const META_SHEETS = 'MetaSheets';
30+
const tabId = core.getRegistry(rootNode, META_SHEETS)
31+
.find(desc => desc.order === 0)
32+
.SetID;
33+
34+
core.addMember(rootNode, META_ASPECT_SET_NAME, utils);
35+
core.addMember(rootNode, tabId, utils);
36+
37+
// Add 'Code' from 'pipelines' as a valid child
38+
core.setChildMeta(utils, META['pipeline.Code']);
39+
40+
// Set the default visualizer to TabbedTextEditor
41+
core.setRegistry(utils, 'validVisualizers', 'TabbedTextEditor');
42+
}
43+
}
44+
];
45+
46+
const Updates = {};
47+
48+
Updates.getAvailableUpdates = function(core, rootNode) {
49+
return Q.all(allUpdates.map(update => update.isNeeded(core, rootNode)))
50+
.then(isNeeded => {
51+
const updates = allUpdates.filter((update, i) => isNeeded[i]);
52+
return updates;
53+
});
54+
};
55+
56+
Updates.getUpdates = function(names) {
57+
if (names) {
58+
return allUpdates.filter(update => names.includes(update.name));
59+
}
60+
return allUpdates;
61+
};
62+
63+
Updates.getUpdate = function(name) {
64+
return Updates.getUpdates([name])[0];
65+
};
66+
67+
// Constants
68+
Updates.MIGRATION = 'Migration';
69+
Updates.SEED = 'SeedUpdate';
70+
return Updates;
71+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*globals define*/
2+
/*eslint-env node, browser*/
3+
4+
define([
5+
'deepforge/updates/Updates',
6+
'text!./metadata.json',
7+
'plugin/PluginBase'
8+
], function (
9+
Updates,
10+
pluginMetadata,
11+
PluginBase
12+
) {
13+
'use strict';
14+
15+
pluginMetadata = JSON.parse(pluginMetadata);
16+
17+
/**
18+
* Initializes a new instance of ApplyUpdates.
19+
* @class
20+
* @augments {PluginBase}
21+
* @classdesc This class represents the plugin ApplyUpdates.
22+
* @constructor
23+
*/
24+
var ApplyUpdates = function () {
25+
// Call base class' constructor.
26+
PluginBase.call(this);
27+
this.pluginMetadata = pluginMetadata;
28+
};
29+
30+
/**
31+
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
32+
* This is also available at the instance at this.pluginMetadata.
33+
* @type {object}
34+
*/
35+
ApplyUpdates.metadata = pluginMetadata;
36+
37+
// Prototypical inheritance from PluginBase.
38+
ApplyUpdates.prototype = Object.create(PluginBase.prototype);
39+
ApplyUpdates.prototype.constructor = ApplyUpdates;
40+
41+
/**
42+
* Main function for the plugin to execute. This will perform the execution.
43+
* Notes:
44+
* - Always log with the provided logger.[error,warning,info,debug].
45+
* - Do NOT put any user interaction logic UI, etc. inside this method.
46+
* - callback always has to be called even if error happened.
47+
*
48+
* @param {function(string, plugin.PluginResult)} callback - the result callback
49+
*/
50+
ApplyUpdates.prototype.main = async function (callback) {
51+
// Retrieve the updates to apply
52+
const config = this.getCurrentConfig();
53+
const updateNames = config.updates || [];
54+
55+
if (!updateNames.length) {
56+
this.result.setSuccess(true);
57+
return callback(null, this.result);
58+
}
59+
60+
// Apply each of the updates
61+
const updates = Updates.getUpdates(updateNames);
62+
63+
for (let i = 0, len = updates.length; i < len; i++) {
64+
const update = updates[i];
65+
this.logger.info(`Applying update: ${update.name} to ${this.projectId}`);
66+
await update.apply(this.core, this.rootNode, this.META);
67+
}
68+
69+
// Save the project
70+
await this.save(`Applied project updates: ${updateNames.join(",")}`);
71+
72+
this.result.setSuccess(true);
73+
callback(null, this.result);
74+
};
75+
76+
return ApplyUpdates;
77+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"id": "ApplyUpdates",
3+
"name": "ApplyUpdates",
4+
"version": "0.1.0",
5+
"description": "",
6+
"icon": {
7+
"class": "glyphicon glyphicon-cog",
8+
"src": ""
9+
},
10+
"disableServerSideExecution": false,
11+
"disableBrowserSideExecution": false,
12+
"writeAccessRequired": false,
13+
"configStructure": []
14+
}

src/plugins/CheckLibraries/CheckLibraries.js

Lines changed: 0 additions & 178 deletions
This file was deleted.

0 commit comments

Comments
 (0)