Repository: aurora Updated Branches: refs/heads/master 62e46cdea -> 364eac5d1
Add build and unit test pipeline for new Scheduler UI (using Preact). Reviewed at https://reviews.apache.org/r/61864/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/364eac5d Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/364eac5d Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/364eac5d Branch: refs/heads/master Commit: 364eac5d1690e51e9796c712e4fd5f09977ccd2a Parents: 62e46cd Author: David McLaughlin <[email protected]> Authored: Thu Aug 24 16:40:38 2017 -0700 Committer: David McLaughlin <[email protected]> Committed: Thu Aug 24 16:40:38 2017 -0700 ---------------------------------------------------------------------- .gitignore | 4 + build.gradle | 79 +++++++++++--------- settings.gradle | 2 +- .../scheduler/http/JettyServerModule.java | 1 + .../scheduler/assets/scheduler/new-index.html | 31 ++++++++ ui/.babelrc | 3 + ui/.eslintrc | 29 +++++++ ui/karma.conf.js | 23 ++++++ ui/package.json | 52 +++++++++++++ ui/src/main/js/components/Home.js | 4 + .../main/js/components/__tests__/Home-test.js | 12 +++ ui/src/main/js/index.js | 21 ++++++ ui/webpack.config.js | 42 +++++++++++ 13 files changed, 268 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index b4e2bcb..2f24af5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.iws *.pyc *~ +*bundle.js* .gradle /.cache/ /.coverage @@ -33,3 +34,6 @@ /out/ /requirements.txt /third_party/ +/ui/dist/ +/ui/node_modules/ +/ui/out/ http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/build.gradle ---------------------------------------------------------------------- diff --git a/build.gradle b/build.gradle index c2c402f..0467338 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ plugins { id 'com.eriwen.gradle.js' version '1.12.1' id 'com.github.ben-manes.versions' version '0.11.3' id 'com.github.hierynomus.license' version '0.11.0' + id 'com.moowork.node' version '1.1.1' id 'me.champeau.gradle.jmh' version '0.2.0' } @@ -130,6 +131,50 @@ For more details, please see https://issues.apache.org/jira/browse/AURORA-1169 } } +/** + * This gradle project contains the logic to bootstrap and build the UI bundle using NodeJS. + * The core logic of UI building is delegated to npm and Webpack. Webpack writes the UI bundle + * into the resources directory of the Scheduler, so it must be built before the Scheduler. + */ +project(':ui') { + apply plugin: 'com.moowork.node' + node { + download = true + } + + task test(type: NpmTask, overwrite: true) { + inputs.files(fileTree('src')) + outputs.files(fileTree('dist')) + args = ['test'] + } + + task install(type: NpmTask) { + inputs.files(file('package.json')) + outputs.files(fileTree('node_modules')) + // Install into the project dir to sandbox everything under ui/ + args = ['install'] + } + + task lint(type: NpmTask, dependsOn: 'install') { + inputs.files(fileTree('src')) + outputs.files(fileTree('.')) + args = ['run-script', 'lint'] + } + + task webpack(type: NodeTask, dependsOn: 'install') { + inputs.files(fileTree('src')) + outputs.files(sourceSets.main.java) + script = file('node_modules/.bin/webpack') + } + + tasks.build.dependsOn(lint) + tasks.build.dependsOn(webpack) + tasks.build.dependsOn(npm_test) +} +// Make sure UI webpack is run as part of 'processResources --continuous'. Also makes sure when +// building the Scheduler JAR, the JS bundle is built first. +tasks.processResources.dependsOn(':ui:webpack') + /* This gradle project contains the annotation procesor from * com.twitter.common.args and related dependencies. It needs to be outside of * the commons project because gradle needs to compile the annotation processor @@ -447,40 +492,6 @@ pmdTest { ruleSetFiles = files('config/pmd/common.xml', 'config/pmd/test.xml') } -/** - * There is a jshint target recommended in the README for gradle-js-plugin - * but it does not work. This workaround from here: - * https://github.com/eriwen/gradle-js-plugin/issues/73 - */ -task jsHint(type:com.eriwen.gradle.js.tasks.JsHintTask) { - source = fileTree("src/main/resources/$httpAssetsPath/js/") - dest file("${buildDir}/jshint.out") - // Set this to false once JS code complies with JSHint. - ignoreExitCode false - outputToStdOut true - jshint.options = [ - // See: http://www.jshint.com/docs/options/ for explanation. - browser: true, - camelcase: true, - curly: true, - eqeqeq: true, - indent: 2, - maxlen: 100, - quotmark: true, - trailing: true, - undef: true, - unused: 'vars', - white: true - ] - jshint.predef = [ - '_': true, - 'angular': true, - 'moment': true, - 'Thrift': true - ] -} -tasks.checkstyleMain.dependsOn(jsHint) - tasks.withType(Test) { maxParallelForks = Runtime.runtime.availableProcessors() } http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/settings.gradle ---------------------------------------------------------------------- diff --git a/settings.gradle b/settings.gradle index b097e2f..264426d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,4 +12,4 @@ * limitations under the License. */ rootProject.name = 'aurora' -include 'api', 'buildSrc', 'commons-args', 'commons' +include 'ui', 'api', 'buildSrc', 'commons-args', 'commons' http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java b/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java index f7e72e7..e29bb41 100644 --- a/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java +++ b/src/main/java/org/apache/aurora/scheduler/http/JettyServerModule.java @@ -324,6 +324,7 @@ public class JettyServerModule extends AbstractModule { .put("/graphview(?:/index.html)?", "/assets/graphview/graphview.html") .put("/graphview/(.*)", "/assets/graphview/$1") .put("/(?:scheduler|updates)(?:/.*)?", "/assets/scheduler/index.html") + .put("/beta/(?:scheduler|updates)(?:/.*)?", "/assets/scheduler/new-index.html") .put("/slaves", "/agents") .build(); http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/src/main/resources/scheduler/assets/scheduler/new-index.html ---------------------------------------------------------------------- diff --git a/src/main/resources/scheduler/assets/scheduler/new-index.html b/src/main/resources/scheduler/assets/scheduler/new-index.html new file mode 100644 index 0000000..d59a6f5 --- /dev/null +++ b/src/main/resources/scheduler/assets/scheduler/new-index.html @@ -0,0 +1,31 @@ +<!doctype html> +<!-- + 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. + --> +<html lang='en'> + <head> + <meta charset='utf-8'> + <meta name='google' value='notranslate'> + <link rel='icon' href='/assets/images/aurora.png' type='image/png'/> + <title>Aurora</title> + <!-- Load our css at the end so we can override bootstrap css properties as needed --> + <link href='/assets/bower_components/bootstrap/dist/css/bootstrap.min.css' rel='stylesheet'> + </head> + <body> + <div id="root"></div> + <script src='/assets/bower_components/jquery/dist/jquery.js'></script> + <!-- Thrift --> + <script src='/assets/js/thrift.js'></script> + <script src='/apiclient/api_types.js'></script> + <script src='/apiclient/ReadOnlyScheduler.js'></script> + <script src="/assets/js/bundle.js"></script> + </body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/.babelrc ---------------------------------------------------------------------- diff --git a/ui/.babelrc b/ui/.babelrc new file mode 100644 index 0000000..86c445f --- /dev/null +++ b/ui/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "react"] +} http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/.eslintrc ---------------------------------------------------------------------- diff --git a/ui/.eslintrc b/ui/.eslintrc new file mode 100644 index 0000000..355b6a8 --- /dev/null +++ b/ui/.eslintrc @@ -0,0 +1,29 @@ +{ + // babel parser to support ES features + "parser": "babel-eslint", + "extends": [ + "standard", + "standard-react" + ], + "globals": { + "Thrift": true, + "ReadOnlySchedulerClient" + }, + "rules": { + "arrow-parens": [2, "always"], + // not covered in standard + "no-var": 2, + "prefer-const": 2, + // overrides of the standard style + "curly": [2, "all"], + "max-len": [2, 100, 4], + "semi": [2, "always"], + "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], + "wrap-iife": [2, "outside"], + // overrides of the standard-react style + "react/jsx-sort-props": 2, + "react/prop-types": 0, + "react/sort-prop-types": 2, + "camelcase": [2, {"properties": "never"}], + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/karma.conf.js ---------------------------------------------------------------------- diff --git a/ui/karma.conf.js b/ui/karma.conf.js new file mode 100644 index 0000000..d42cda7 --- /dev/null +++ b/ui/karma.conf.js @@ -0,0 +1,23 @@ +var webpackConfig = require('./webpack.config.js'); + +module.exports = function(config) { + config.set({ + basePath: '', + frameworks: ['jasmine'], + files: [ + 'src/**/*-test.js' + ], + preprocessors: { + 'src/**/*-test.js': ['webpack'] + }, + reporters: ['spec'], + webpack: webpackConfig, + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['PhantomJS'], + singleRun: true, + concurrency: Infinity + }) +} http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/package.json ---------------------------------------------------------------------- diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 0000000..f712518 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,52 @@ +{ + "name": "apache-aurora", + "version": "1.0.0", + "description": "UI project for Apache Aurora", + "main": "index.js", + "dependencies": { + "preact": "^8.2.1", + "preact-compat": "^3.17.0", + "react-router-dom": "^4.1.2" + }, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^7.2.3", + "babel-loader": "^7.1.1", + "babel-plugin-react-transform": "^2.0.2", + "babel-plugin-transform-react-jsx": "^6.24.1", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "chai": "^4.1.1", + "css-loader": "^0.28.5", + "eslint": "^4.4.1", + "eslint-config-standard": "^10.2.1", + "eslint-config-standard-react": "^5.0.0", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-react": "^7.2.1", + "eslint-plugin-standard": "^3.0.1", + "jasmine-core": "^2.7.0", + "karma": "^1.7.0", + "karma-cli": "^1.0.1", + "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.4", + "karma-spec-reporter": "0.0.31", + "karma-webpack": "^2.0.4", + "node-sass": "^4.5.3", + "preact-jsx-chai": "^2.2.1", + "sass-loader": "^6.0.6", + "style-loader": "^0.18.2", + "webpack": "^2.6.1" + }, + "scripts": { + "lint": "eslint ui/src/main/js --ext .js", + "test": "NODE_ENV=test karma start karma.conf.js" + }, + "repository": { + "type": "git", + "url": "https://git-wip-us.apache.org/repos/asf/aurora" + }, + "author": "", + "license": "Apache-2.0" +} http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/src/main/js/components/Home.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/components/Home.js b/ui/src/main/js/components/Home.js new file mode 100644 index 0000000..91d60b3 --- /dev/null +++ b/ui/src/main/js/components/Home.js @@ -0,0 +1,4 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +export default () => <div>Hello, World!</div>; http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/src/main/js/components/__tests__/Home-test.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/components/__tests__/Home-test.js b/ui/src/main/js/components/__tests__/Home-test.js new file mode 100644 index 0000000..2a80958 --- /dev/null +++ b/ui/src/main/js/components/__tests__/Home-test.js @@ -0,0 +1,12 @@ +import React from 'react'; +import Home from '../Home'; + +import chai, { expect } from 'chai'; +import assertJsx from 'preact-jsx-chai'; +chai.use(assertJsx); + +describe('Home', () => { + it('Should render Hello, World!', () => { + expect(<Home/>).to.deep.equal(<div>Hello, World!</div>); + }); +}); http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/src/main/js/index.js ---------------------------------------------------------------------- diff --git a/ui/src/main/js/index.js b/ui/src/main/js/index.js new file mode 100644 index 0000000..2f7467b --- /dev/null +++ b/ui/src/main/js/index.js @@ -0,0 +1,21 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { BrowserRouter as Router, Route } from 'react-router-dom'; + +import Home from 'components/Home'; + +const SchedulerUI = () => ( + <Router> + <div> + <Route component={Home} exact path='/beta/scheduler' /> + <Route component={Home} exact path='/beta/scheduler/:role' /> + <Route component={Home} exact path='/beta/scheduler/:role/:environment' /> + <Route component={Home} exact path='/beta/scheduler/:role/:environment/:name' /> + <Route component={Home} exact path='/beta/scheduler/:role/:environment/:name/:instance' /> + <Route component={Home} exact path='/beta/scheduler/:role/:environment/:name/update/:uid' /> + <Route component={Home} exact path='/beta/updates' /> + </div> + </Router> +); + +ReactDOM.render(<SchedulerUI />, document.getElementById('root')); http://git-wip-us.apache.org/repos/asf/aurora/blob/364eac5d/ui/webpack.config.js ---------------------------------------------------------------------- diff --git a/ui/webpack.config.js b/ui/webpack.config.js new file mode 100644 index 0000000..e7cd672 --- /dev/null +++ b/ui/webpack.config.js @@ -0,0 +1,42 @@ +var path = require('path'); +var webpack = require('webpack'); + +var SOURCE_PATH = path.resolve(__dirname, 'src/main/js'); +var EXTENSION_PATH = path.resolve(__dirname, 'plugin/js') + +module.exports = { + devtool: 'source-map', + entry: './src/main/js/index', + output: { + path: path.resolve(__dirname, '../src/main/resources/scheduler/assets/js'), + filename: 'bundle.js', + publicPath: '/' + }, + resolve: { + alias: { + react: "preact-compat", + "react-dom": "preact-compat" + }, + extensions: [ '.js' ], + modules: [EXTENSION_PATH, SOURCE_PATH, 'node_modules'] + }, + module: { + rules: [{ + test: /\.js?$/, + loaders: ['babel-loader'], + include: [EXTENSION_PATH, SOURCE_PATH] + }, { + test: /\.scss$/, + use: [{ + loader: 'style-loader' + }, { + loader: 'css-loader' + }, { + loader: 'sass-loader', + options: { + includePaths: [path.resolve(__dirname, 'src/main/sass')] + } + }] + }] + } +};
