Merge pull request #141 from cloudbees/UX-301

[UX-301] Add a js-builder extension/plugin to js-extensions
This commit is contained in:
Tom Fennelly 2016-04-20 15:25:57 +01:00
commit fe35475bcd
6 changed files with 214 additions and 8 deletions

View File

@ -13,7 +13,7 @@
},
"devDependencies": {
"@jenkins-cd/eslint-config-jenkins": "0.0.2",
"@jenkins-cd/js-builder": "0.0.29",
"@jenkins-cd/js-builder": "0.0.31",
"@jenkins-cd/js-test": "1.1.1",
"@kadira/storybook": "^1.11.0",
"babel": "^6.5.2",
@ -33,7 +33,7 @@
},
"dependencies": {
"@jenkins-cd/design-language": "0.0.11",
"@jenkins-cd/js-extensions": "0.0.10",
"@jenkins-cd/js-extensions": "0.0.11",
"@jenkins-cd/js-modules": "0.0.4",
"immutable": "^3.7.6",
"moment": "^2.12.0",

View File

@ -15,7 +15,7 @@
"bundle:watch": "gulp bundle:watch"
},
"devDependencies": {
"@jenkins-cd/js-builder": "0.0.29",
"@jenkins-cd/js-builder": "0.0.31",
"@jenkins-cd/js-test": "1.1.1",
"babel-eslint": "^6.0.0",
"babel-preset-es2015": "^6.6.0",
@ -27,7 +27,7 @@
},
"dependencies": {
"@jenkins-cd/design-language": "0.0.11",
"@jenkins-cd/js-extensions": "0.0.10",
"@jenkins-cd/js-extensions": "0.0.11",
"@jenkins-cd/js-modules": "0.0.4",
"history": "2.0.1",
"react": "0.14.7",

View File

@ -0,0 +1,154 @@
/**
* Jenkins js-builder extension plugin. https://github.com/jenkinsci/js-builder
*
* Adds some js-extensions specific behaviour to the build.
*/
var dependencies = __builder.dependencies;
var maven = __builder.maven;
var paths = __builder.paths;
var logger = __builder.logger;
var fs = require('fs');
var path = require('path');
var cwd = process.cwd();
var jsExtensionsYAMLFile = findExtensionsYAMLFile();
/**
* Install the js-builder plugin. This function will be called by js-builder.
*/
exports.install = function() {
try {
if (jsExtensionsYAMLFile) {
// Transform the jenkins-js-extensions.yaml file + enrich with some info
transformToJSON();
// Generate a jenkins-js-extensions.jsx from the jenkins-js-extensions.yaml.
var jsxFile = transformToJSX();
// Generate a bundle for the extensions.
createBundle(jsxFile);
}
} catch (e) {
logger.logError(e);
}
};
exports.readYAMLFile = function(file) {
if (!file || !fs.existsSync(file)) {
return undefined;
}
var rawYAML = fs.readFileSync(file, "utf-8");
return require('js-yaml').load(rawYAML);
};
exports.getJSExtensions = function() {
return exports.readYAMLFile(jsExtensionsYAMLFile);
};
exports.yamlToJSON = function(sourceFile, targetFile, transformer) {
var asJSON = exports.readYAMLFile(sourceFile);
if (transformer) {
asJSON = transformer(asJSON);
}
fs.writeFileSync(targetFile, JSON.stringify(asJSON, undefined, 4));
};
/**
* Find the jenkins-js-extension.yaml file in the src paths.
*/
function findExtensionsYAMLFile() {
for (var i = 0; i < paths.srcPaths.length; i++) {
var srcPath = path.resolve(cwd, paths.srcPaths[i]);
var extFile = path.resolve(srcPath, 'jenkins-js-extension.yaml');
if (fs.existsSync(extFile)) {
return extFile;
}
}
return undefined;
}
function transformToJSON() {
// If there's a jenkins-js-extensions.yaml, transform it to jenkins-js-extensions.json
// in the target/classes dir, making it easier to consume on the backend (HPI extension discovery).
if (jsExtensionsYAMLFile) {
assertHasJenkinsJsExtensionsDependency('Your project defines a jenkins-js-extensions.yaml file\n\t- Path: ' + jsExtensionsYAMLFile);
var jsExtensionsJSONFile = cwd + '/target/classes/jenkins-js-extension.json';
paths.mkdirp('target/classes');
exports.yamlToJSON(jsExtensionsYAMLFile, jsExtensionsJSONFile, function(json) {
if (maven.isHPI()) {
json.hpiPluginId = maven.getArtifactId();
}
return json;
});
}
}
function transformToJSX() {
// If there's a jenkins-js-extensions.yaml, transform it to jenkins-js-extensions.jsx
if (jsExtensionsYAMLFile) {
assertHasJenkinsJsExtensionsDependency('Your project defines a jenkins-js-extensions.yaml file\n\t- Path: ' + jsExtensionsYAMLFile);
var extensionsMeta = exports.getJSExtensions();
if (!extensionsMeta || !extensionsMeta.extensions || extensionsMeta.extensions.length === 0) {
return undefined;
}
var extensions = extensionsMeta.extensions;
var srcRoot = path.dirname(jsExtensionsYAMLFile);
var targetRoot = cwd + '/target';
var relPath = path.relative(targetRoot, srcRoot);
var jsxFilePath = targetRoot + '/jenkins-js-extension.jsx';
var jsxFileContent = '';
jsxFileContent += "//\n";
jsxFileContent += "// NOTE: This JSX file is generated and should NOT be added to source control.\n";
jsxFileContent += "//\n";
jsxFileContent += "\n";
// Add all the top level imports...
for (var i1 = 0; i1 < extensions.length; i1++) {
var extension = extensions[i1];
extension.importAs = 'component_' + i1;
jsxFileContent += "import " + extension.importAs + " from '" + relPath + "/" + extension.component + ".jsx';\n";
}
// Add the js-modules import of the extensions and add the code to register all
// of the extensions in the shared store.
jsxFileContent += "require('@jenkins-cd/js-modules').import('jenkins-cd:js-extensions').onFulfilled(function(extensions) {\n";
for (var i2 = 0; i2 < extensions.length; i2++) {
var extension = extensions[i2];
jsxFileContent += " extensions.store.addExtension('" + extension.extensionPoint + "', " + extension.importAs + ");\n";
}
jsxFileContent += "});";
fs.writeFileSync(jsxFilePath, jsxFileContent);
return jsxFilePath;
}
return undefined;
}
function createBundle(jsxFile) {
__builder.bundle(jsxFile)
.namespace(maven.getArtifactId())
.withExternalModuleMapping('@jenkins-cd/js-extensions', 'jenkins-cd:js-extensions')
.withExternalModuleMapping('@jenkins-cd/design-language', 'jenkins-cd:jdl')
.withExternalModuleMapping('react', 'react:react')
.withExternalModuleMapping('react-dom', 'react:react-dom')
.inDir('target/classes/org/jenkins/ui/jsmodules/' + maven.getArtifactId());
}
function hasJenkinsJsExtensionsDep() {
return (dependencies.getDependency('@jenkins-cd/js-extensions') !== undefined);
}
function assertHasJenkinsJsExtensionsDependency(message) {
if(!hasJenkinsJsExtensionsDep()) {
dependencies.exitOnMissingDependency('@jenkins-cd/js-extensions', message);
}
}

View File

@ -1,9 +1,14 @@
{
"name": "@jenkins-cd/js-extensions",
"version": "0.0.10",
"version": "0.0.11",
"description": "Jenkins Extension Store",
"main": "index.js",
"files": ["index.js","dist","README.md"],
"files": [
"index.js",
"dist",
"@jenkins-cd",
"README.md"
],
"scripts": {
"build": "rm -rf dist && mkdir dist && jsx src/ExtensionPoint.jsx > dist/ExtensionPoint.js && cp src/store.js dist/",
"test": "gulp test",
@ -16,12 +21,13 @@
"react-dom": "^0.14.7"
},
"devDependencies": {
"gulp": "^3.9.1",
"@jenkins-cd/js-builder": "0.0.22",
"@jenkins-cd/js-builder": "0.0.31",
"@jenkins-cd/js-test": "1.1.1",
"gulp": "^3.9.1",
"react-tools": "^0.13.3"
},
"dependencies": {
"js-yaml": "^3.6.0",
"@jenkins-cd/js-modules": "0.0.2"
}
}

View File

@ -0,0 +1,25 @@
describe("js-builder plugin test", function () {
it("- test readYAMLFile", function () {
var jsBuilder = require('../@jenkins-cd/js-builder');
var asJSON = jsBuilder.readYAMLFile('./spec/sample-extensions.yaml');
assertSampleJSONOkay(asJSON);
});
it("- test yamlToJSON", function () {
var jsBuilder = require('../@jenkins-cd/js-builder');
jsBuilder.yamlToJSON('./spec/sample-extensions.yaml', './target/sample-extensions.json');
var asJSON = require('../target/sample-extensions.json');
assertSampleJSONOkay(asJSON);
});
function assertSampleJSONOkay(asJSON) {
expect(asJSON.id).toBe('com.example.my.plugin');
expect(asJSON.artefacts.page.id).toBe('about-my-plugin');
expect(asJSON.artefacts.components[0].id).toBe('MyNeatButton');
expect(asJSON.artefacts.components[1].id).toBe('SuperList');
}
});

View File

@ -0,0 +1,21 @@
id: com.example.my.plugin
version: 3.14.15
artefacts:
page:
id: about-my-plugin
url: /some/page/route
main: index.html
components:
- id: MyNeatButton
main: neat-button/index.jsx
- id: SuperList
main: super-list/index.jsx
integrations:
- type: menuitem
location: blueocean.nav.footer
url: http://example.com/myPlugin/
link-text: More about FooPlugin
- type: menuitem
location: blueocean.nav.footer
url: route://some/page/route
link-text: Foo Plugin Report