From 977defd4868d8dfce69900217e8028a8c772c53f Mon Sep 17 00:00:00 2001 From: Vitaly Kramskikh Date: Mon, 25 Nov 2013 21:22:00 +0400 Subject: [PATCH] Grunt: The JavaScript Task Runner Change-Id: Ibab5789050ea2a14e02fad8c0aa7877cb39521bb --- .gitignore | 2 + docs/develop/env.rst | 18 ++++-- nailgun/Gruntfile.js | 56 +++++++++++++++++++ nailgun/build.js | 24 -------- nailgun/package.json | 18 ++++++ nailgun/static/js/app.js | 2 +- nailgun/static/js/main.js | 3 +- nailgun/static/js/models.js | 5 +- nailgun/static/js/utils.js | 9 --- .../js/views/cluster_page_tabs/nodes_tab.js | 2 +- nailgun/static/js/views/common.js | 1 - nailgun/static/js/views/dialogs.js | 16 +++--- run_tests.sh | 19 ++----- 13 files changed, 106 insertions(+), 69 deletions(-) create mode 100644 nailgun/Gruntfile.js delete mode 100644 nailgun/build.js create mode 100644 nailgun/package.json diff --git a/.gitignore b/.gitignore index 2f21b31fca..27ef3d5961 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ nosetests.xml nailgun.log lock +node_modules + .idea .DS_Store diff --git a/docs/develop/env.rst b/docs/develop/env.rst index b66fbe8758..c8be2da6ff 100644 --- a/docs/develop/env.rst +++ b/docs/develop/env.rst @@ -73,12 +73,18 @@ Setup for Nailgun Unit Tests Setup for Web UI Tests ---------------------- -#. Install NodeJS (on Debian, you may need to use 'apt-get install -t - experimental' to get the latest npm, on Ubuntu 12.04, use nodejs package - instead of nodejs-legacy)) and CasperJS:: +#. Install NodeJS and JS dependencies:: - sudo apt-get install npm nodejs-legacy phantomjs - sudo npm install -g jslint requirejs + sudo add-apt-repository ppa:chris-lea/node.js + sudo apt-get update + sudo apt-get install nodejs + sudo npm install -g grunt-cli + cd nailgun + npm install + +#. Install CasperJS:: + + sudo apt-get install phantomjs cd ~ git clone git://github.com/n1k0/casperjs.git cd casperjs @@ -113,7 +119,7 @@ Running Nailgun in Fake Mode #. (optional) To create a compressed version of UI and put it into static_compressed dir:: - r.js -o build.js dir=static_compressed + grunt build --static-dir=static_compressed Astute and Naily ---------------- diff --git a/nailgun/Gruntfile.js b/nailgun/Gruntfile.js new file mode 100644 index 0000000000..791a9f4699 --- /dev/null +++ b/nailgun/Gruntfile.js @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Mirantis, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. +**/ +module.exports = function(grunt) { + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + requirejs: { + compile: { + options: { + baseUrl: '.', + appDir: 'static', + dir: grunt.option('static-dir') || '/tmp/static_compressed', + mainConfigFile: 'static/js/main.js', + modules: [{name: 'js/main'}], + waitSeconds: 60, + optimize: 'uglify2', + } + } + }, + jslint: { + client: { + src: [ + 'static/js/*.js', + 'static/js/views/*.js', + ], + directives: { + predef: ['requirejs', 'require', 'define', 'app', 'Backbone', '$', '_'], + ass: true, + browser: true, + unparam: true, + nomen: true, + eqeq: true, + vars: true, + white: true, + es5: false + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-requirejs'); + grunt.loadNpmTasks('grunt-jslint'); + grunt.registerTask('build', ['requirejs']); +}; diff --git a/nailgun/build.js b/nailgun/build.js deleted file mode 100644 index 9e52ab3f7d..0000000000 --- a/nailgun/build.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2013 Mirantis, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. -**/ -({ - baseUrl: ".", - appDir: "static", - dir: "/tmp/static", - mainConfigFile: "static/js/main.js", - modules: [{name: "js/main"}], - waitSeconds: 60, - optimize: "uglify2" -}) diff --git a/nailgun/package.json b/nailgun/package.json new file mode 100644 index 0000000000..08cdd8aa56 --- /dev/null +++ b/nailgun/package.json @@ -0,0 +1,18 @@ +{ + "name": "fuel-web", + "version": "0.0.1", + "repository": { + "type": "git", + "url": "https://github.com/stackforge/fuel-web.git" + }, + "devDependencies": { + "grunt": "~0.4.2", + "jslint": "~0.2.5", + "requirejs": "~2.1.9", + "uglifyjs": "~2.3.6", + "less": "~1.5.1", + "grunt-jslint": "~1.1.1", + "grunt-contrib-requirejs": "~0.4.1", + "grunt-contrib-less": "~0.8.2" + } +} \ No newline at end of file diff --git a/nailgun/static/js/app.js b/nailgun/static/js/app.js index 0e49f6c472..7f8b74cbbe 100644 --- a/nailgun/static/js/app.js +++ b/nailgun/static/js/app.js @@ -83,7 +83,7 @@ function(Coccyx, coccyxMixins, models, commonViews, ClusterPage, NodesTab, Clust app.page.tab.routeScreen(tabOptions); return; } - } catch(e) {} + } catch (ignore) {} } var cluster, tasks; diff --git a/nailgun/static/js/main.js b/nailgun/static/js/main.js index beed13527b..eeb724677a 100644 --- a/nailgun/static/js/main.js +++ b/nailgun/static/js/main.js @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations * under the License. **/ -'use strict'; requirejs.config({ baseUrl: 'static', urlArgs: '_=' + (new Date()).getTime(), @@ -63,6 +62,7 @@ requirejs.config({ i18next: { deps: ['text!i18n/translation.json', 'jquery'], init: function(translation, $) { + 'use strict'; $.i18n.init({resStore: JSON.parse(translation)}); } }, @@ -85,5 +85,6 @@ require([ 'jquery', 'underscore', 'backbone', 'stickit', 'deepModel', 'coccyx', 'i18next', 'bootstrap', 'retina', 'jquery-checkbox', 'jquery-timeout', 'jquery-ui', 'jquery-autoNumeric', 'app' ], function() { + 'use strict'; require('app').initialize(); }); diff --git a/nailgun/static/js/models.js b/nailgun/static/js/models.js index 3e6ac9a578..2979ca331b 100644 --- a/nailgun/static/js/models.js +++ b/nailgun/static/js/models.js @@ -17,7 +17,6 @@ define(['utils', 'deepModel'], function(utils) { 'use strict'; var models = {}; - var collections = {}; models.Release = Backbone.Model.extend({ constructorName: 'Release', @@ -133,7 +132,7 @@ define(['utils', 'deepModel'], function(utils) { } else if (resourceName == 'interfaces') { resource = this.get('meta').interfaces.length; } - } catch (e) {} + } catch (ignore) {} if (_.isNaN(resource)) { resource = 0; } @@ -203,7 +202,7 @@ define(['utils', 'deepModel'], function(utils) { var id; try { id = this.get('result').release_info.release_id; - } catch(e) {} + } catch (ignore) {} return id; } }); diff --git a/nailgun/static/js/utils.js b/nailgun/static/js/utils.js index f632409df6..306faa48c3 100644 --- a/nailgun/static/js/utils.js +++ b/nailgun/static/js/utils.js @@ -37,15 +37,6 @@ define(['require'], function(require) { var urlRegexp = /(?:https?:\/\/([\-\w\.]+)+(:\d+)?(\/([\w\/_\-\.]*(\?\S+)?)?)?)/g; return utils.linebreaks(text).replace(urlRegexp, utils.composeLink); }, - forceWebkitRedraw: function(el) { - if (window.isWebkit) { - el.each(function() { - this.style.webkitTransform = 'scale(1)'; - var dummy = this.offsetHeight; - this.style.webkitTransform = ''; - }); - } - }, showErrorDialog: function(options, parentView) { parentView = parentView || app.page; var dialogViews = require('views/dialogs'); // avoid circular dependencies diff --git a/nailgun/static/js/views/cluster_page_tabs/nodes_tab.js b/nailgun/static/js/views/cluster_page_tabs/nodes_tab.js index 0f5ce38de3..6917a36c71 100644 --- a/nailgun/static/js/views/cluster_page_tabs/nodes_tab.js +++ b/nailgun/static/js/views/cluster_page_tabs/nodes_tab.js @@ -816,7 +816,7 @@ function(utils, models, commonViews, dialogViews, nodesManagementPanelTemplate, var operatingSystem; try { operatingSystem = this.node.collection.cluster.get('release').get('operating_system'); - } catch(e){} + } catch (ignore) {} operatingSystem = operatingSystem || 'OS'; var labels = { offline: $.t('cluster_page.nodes_tab.node.status.offline'), diff --git a/nailgun/static/js/views/common.js b/nailgun/static/js/views/common.js index 355f4b966d..e38994defa 100644 --- a/nailgun/static/js/views/common.js +++ b/nailgun/static/js/views/common.js @@ -39,7 +39,6 @@ function(utils, models, dialogViews, navbarTemplate, nodesStatsTemplate, notific app.navbar.setActive(_.result(this, 'navbarActiveElement')); }, updateBreadcrumbs: function() { - var breadcrumbsPath = _.isFunction(this.breadcrumbsPath) ? this.breadcrumbsPath() : this.breadcrumbsPath; app.breadcrumbs.setPath(_.result(this, 'breadcrumbsPath')); }, updateTitle: function() { diff --git a/nailgun/static/js/views/dialogs.js b/nailgun/static/js/views/dialogs.js index 04021c949a..39738aa612 100644 --- a/nailgun/static/js/views/dialogs.js +++ b/nailgun/static/js/views/dialogs.js @@ -56,7 +56,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl var options = {type: 'local', source: 'api', level: 'error'}; logsLink = '#cluster/' + app.page.model.id + '/logs/' + utils.serializeTabOptions(options); } - } catch(e) {} + } catch (ignore) {} this.$('.modal-body').removeClass().addClass('modal-body'); this.$('.modal-body').html(views.Dialog.prototype.errorMessageTemplate({logsLink: logsLink})); }, @@ -349,7 +349,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl var description = ''; try { description = release.get('modes_metadata')[mode].description; - } catch(e) {} + } catch (ignore) {} this.$('.mode-description').text(description); }, beforeClusterCreation: function(cluster) { @@ -370,7 +370,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl beforeSettingsSaving: function(settings) { try { settings.get('editable').common.libvirt_type.value = this.$('input[name=hypervisor]:checked').val(); - } catch(e) { + } catch (e) { return (new $.Deferred()).reject(); } return (new $.Deferred()).resolve(); @@ -429,7 +429,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl storageSettings.images_ceph.value = true; } } - } catch(e) { + } catch (e) { return (new $.Deferred()).reject(); } return (new $.Deferred()).resolve(); @@ -458,7 +458,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl additionalServices.murano.value = this.$('input[name=murano]').is(':checked'); additionalServices.heat.value = this.$('input[name=murano]').is(':checked'); } - } catch(e) { + } catch (e) { return (new $.Deferred()).reject(); } return (new $.Deferred()).resolve(); @@ -638,7 +638,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl } else if (name == 'max_speed' || name == 'current_speed') { value = utils.showBandwidth(value); } - } catch (e) {} + } catch (ignore) {} return value; }, showSummary: function(meta, group) { @@ -665,7 +665,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl var bandwidths = _.groupBy(_.pluck(meta.interfaces, 'current_speed'), utils.showBandwidth); summary = _.map(_.keys(bandwidths).sort(), function(bandwidth) {return bandwidths[bandwidth].length + ' x ' + bandwidth;}).join(', '); } - } catch (e) {} + } catch (ignore) {} return summary; }, sortEntryProperties: function(entry) { @@ -767,7 +767,7 @@ function(require, utils, models, simpleMessageTemplate, createClusterWizardTempl return _.pick(node.attributes, 'id', 'cluster_id', 'pending_roles', 'pending_addition', 'pending_deletion'); }); }; - var deferred = this.nodes.sync('update', this.nodes) + this.nodes.sync('update', this.nodes) .done(_.bind(function() { this.$el.modal('hide'); app.page.tab.model.fetch(); diff --git a/run_tests.sh b/run_tests.sh index b9d3915ba2..e58e9cbfac 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -69,9 +69,8 @@ if [ -n "$ui_test_files" ]; then fi function clean { - echo "cleaning *.pyc, *.json, *.log, *.pid files" + echo "cleaning *.pyc, *.log, *.pid files" find . -type f -name "*.pyc" -delete - rm -f *.json rm -f *.log rm -f *.pid } @@ -107,20 +106,10 @@ if [ $just_flake8 -eq 1 ]; then fi function run_jslint { - which jslint > /dev/null - if [ $? -ne 0 ]; then - echo "JSLint is not installed; install by running:" - echo "sudo apt-get install npm" - echo "sudo npm install -g jslint" - return 1 - fi ( cd nailgun - jsfiles=$(find static/js -type f | grep -v ^static/js/libs/ | grep \\.js$) - jslint_predef=(requirejs require define app Backbone $ _ alert confirm) - jslint_options="$(echo ${jslint_predef[@]} | sed 's/^\| / --predef=/g') --browser=true --nomen=true --eqeq=true --vars=true --white=true --es5=false" - jslint $jslint_options $jsfiles - ) || return 1 + grunt jslint + ) } if [ $just_jslint -eq 1 ]; then @@ -151,7 +140,7 @@ function run_ui_tests { echo -n "Compressing UI... " compressed_static_dir=/tmp/static_compressed rm -rf $compressed_static_dir && mkdir -p $compressed_static_dir - r.js -o build.js dir=$compressed_static_dir > /dev/null + grunt build --static-dir=$compressed_static_dir > /dev/null if [ $? -ne 0 ]; then echo "Failed!" exit 1