Browse Source

Revert "web: rewrite interface in react"

Revert "Fix publish-openstack-javascript-content"

This reverts commit ca199eb9db.
This reverts commit 1082faae95.

This appears to remove the tarball publishing system that we rely on.

Change-Id: Id746fb826dfc01b157c5b772adc1d2991ddcd93a
changes/11/606611/1
James E. Blair 3 years ago
parent
commit
3dba813c64
95 changed files with 5928 additions and 5969 deletions
  1. +8
    -0
      .babelrc
  2. +7
    -0
      .eslintrc
  3. +20
    -14
      .zuul.yaml
  4. +0
    -1
      MANIFEST.in
  5. +1
    -5
      TESTING.rst
  6. +18
    -83
      doc/source/admin/installation.rst
  7. +84
    -49
      doc/source/developer/javascript.rst
  8. +86
    -0
      package.json
  9. +21
    -0
      playbooks/dashboard/multi.yaml
  10. +13
    -14
      playbooks/dashboard/run.yaml
  11. +0
    -11
      releasenotes/notes/react-zuul-a593c7627ca22b37.yaml
  12. +2
    -2
      tests/unit/test_web.py
  13. +8
    -8
      tests/unit/test_web_urls.py
  14. +2
    -4
      tools/pip.sh
  15. +17
    -0
      tsconfig.json
  16. +7
    -0
      tslint.json
  17. +0
    -23
      web/.eslintrc
  18. +1
    -0
      web/.gitignore
  19. +1
    -0
      web/.jshintignore
  20. +21
    -0
      web/.jshintrc
  21. +84
    -0
      web/app-routing.module.ts
  22. +28
    -0
      web/app.component.ts
  23. +73
    -0
      web/app.module.ts
  24. +0
    -1
      web/build
  25. +28
    -0
      web/builds/build.ts
  26. +67
    -0
      web/builds/builds.component.html
  27. +78
    -0
      web/builds/builds.component.ts
  28. +24
    -0
      web/config/main.ejs
  29. +178
    -0
      web/config/status-basic.json
  30. +312
    -0
      web/config/status-openstack.json
  31. +1
    -0
      web/config/status-tree.json
  32. +147
    -0
      web/config/webpack.common.js
  33. +23
    -0
      web/config/webpack.dev.js
  34. +47
    -0
      web/config/webpack.lint.js
  35. +32
    -0
      web/config/webpack.prod.js
  36. +24
    -0
      web/core/core.module.ts
  37. BIN
      web/images/black.png
  38. BIN
      web/images/green.png
  39. BIN
      web/images/grey.png
  40. +0
    -0
      web/images/line-angle.png
  41. +0
    -0
      web/images/line-t.png
  42. +0
    -0
      web/images/line.png
  43. BIN
      web/images/red.png
  44. +17
    -0
      web/jobs/details.ts
  45. +25
    -0
      web/jobs/job.ts
  46. +47
    -0
      web/jobs/jobs.component.html
  47. +54
    -0
      web/jobs/jobs.component.ts
  48. +22
    -0
      web/main.ts
  49. +30
    -0
      web/navigation/navigation.component.html
  50. +34
    -0
      web/navigation/navigation.component.ts
  51. +0
    -41
      web/package.json
  52. BIN
      web/public/favicon.ico
  53. +0
    -17
      web/public/index.html
  54. +0
    -15
      web/public/manifest.json
  55. +0
    -162
      web/src/App.jsx
  56. +0
    -102
      web/src/App.test.jsx
  57. +0
    -133
      web/src/api.js
  58. +0
    -237
      web/src/containers/TableFilters.jsx
  59. +0
    -99
      web/src/containers/status/Change.jsx
  60. +0
    -317
      web/src/containers/status/ChangePanel.jsx
  61. +0
    -64
      web/src/containers/status/ChangePanel.test.jsx
  62. +0
    -54
      web/src/containers/status/ChangeQueue.jsx
  63. +0
    -136
      web/src/containers/status/Pipeline.jsx
  64. BIN
      web/src/images/logo.png
  65. +0
    -83
      web/src/images/logo.svg
  66. +0
    -122
      web/src/index.css
  67. +0
    -40
      web/src/index.js
  68. +0
    -159
      web/src/pages/Builds.jsx
  69. +0
    -99
      web/src/pages/Jobs.jsx
  70. +0
    -289
      web/src/pages/Status.jsx
  71. +0
    -158
      web/src/pages/Stream.jsx
  72. +0
    -79
      web/src/pages/Tenants.jsx
  73. +0
    -94
      web/src/reducers.js
  74. +0
    -119
      web/src/registerServiceWorker.js
  75. +0
    -52
      web/src/routes.js
  76. +944
    -0
      web/status/jquery.zuul.js
  77. +32
    -0
      web/status/status.component.html
  78. +57
    -0
      web/status/status.component.ts
  79. +102
    -0
      web/status/zuulStart.js
  80. +18
    -0
      web/stream/stream.component.css
  81. +24
    -0
      web/stream/stream.component.html
  82. +90
    -0
      web/stream/stream.component.ts
  83. +65
    -0
      web/styles/zuul.css
  84. +18
    -0
      web/tenants/tenant.ts
  85. +40
    -0
      web/tenants/tenants.component.html
  86. +38
    -0
      web/tenants/tenants.component.ts
  87. +18
    -0
      web/zuul/description.ts
  88. +18
    -0
      web/zuul/info.ts
  89. +19
    -0
      web/zuul/infoResponse.ts
  90. +152
    -0
      web/zuul/zuul.service.ts
  91. +3
    -0
      webpack.config.js
  92. +2572
    -3053
      yarn.lock
  93. +4
    -8
      zuul/_setup_hook.py
  94. +22
    -22
      zuul/web/__init__.py
  95. +0
    -0
      zuul/web/static/.keep

+ 8
- 0
.babelrc View File

@ -0,0 +1,8 @@
{
"presets": ['env'],
"plugins": [[
"angularjs-annotate", {
"explicitOnly": false
}
]]
}

+ 7
- 0
.eslintrc View File

@ -0,0 +1,7 @@
parser: babel-eslint
plugins:
- standard
rules:
camelcase: off
extends:
- ./node_modules/eslint-config-standard/eslintrc.json

+ 20
- 14
.zuul.yaml View File

@ -42,20 +42,27 @@
- job:
name: zuul-build-dashboard
parent: build-javascript-content
success-url: 'npm/html/'
success-url: 'npm/html/status.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
vars:
javascript_content_dir: "../zuul/web/static"
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
javascript_content_dir: zuul/web/static
zuul_api_url: https://zuul.openstack.org
run: playbooks/dashboard/run.yaml
- job:
name: zuul-build-dashboard-multi-tenant
parent: zuul-build-dashboard
success-url: 'npm/html/tenants.html'
post-run: playbooks/dashboard/multi.yaml
vars:
zuul_api_url: https://softwarefactory-project.io/zuul
javascript_copy_links: false
- project:
check:
@ -74,16 +81,16 @@
- zuul-build-dashboard
- zuul-build-dashboard-multi-tenant
- nodejs-npm-run-lint:
vars:
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
- nodejs-npm-run-test:
vars:
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
success-url: 'npm/reports/bundle.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
- zuul-stream-functional
- zuul-tox-remote
- pbrx-build-container-images:
@ -106,16 +113,16 @@
- playbooks/zuul-migrate/.*
- zuul-build-dashboard
- nodejs-npm-run-lint:
vars:
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
- nodejs-npm-run-test:
vars:
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
success-url: 'npm/reports/bundle.html'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
- zuul-stream-functional
- zuul-tox-remote
- pbrx-build-container-images:
@ -128,7 +135,6 @@
- publish-openstack-javascript-content:
vars:
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
- openstackzuul-pbrx-push-container-images:
vars:
pbrx_prefix: zuul


+ 0
- 1
MANIFEST.in View File

@ -1,7 +1,6 @@
include AUTHORS
include ChangeLog
include zuul/web/static/*
include zuul/web/static/static/*/*
exclude .gitignore
exclude .gitreview


+ 1
- 5
TESTING.rst View File

@ -38,15 +38,11 @@ As of zuul v3, a running zookeeper is required to execute tests.
*Install javascript dependencies*::
pushd web
yarn install
popd
*Build javascript assets*::
pushd web
yarn build
popd
npm run build:dev
Run The Tests
-------------


+ 18
- 83
doc/source/admin/installation.rst View File

@ -95,7 +95,7 @@ Static External
Sub-URL
Serve a Zuul dashboard from a location below the root URL as part of
presenting integration with other application.
https://softwarefactory-project.io/zuul/ is an example of a Zuul dashboard
https://softwarefactory-project.io/zuul3/ is an example of a Zuul dashboard
that is being served from a Sub-URL.
None of those make any sense for simple non-production oriented deployments, so
@ -121,71 +121,18 @@ simplest reverse-proxy case is::
Static Offload
--------------
To have the Reverse Proxy serve the static html/javascript assets instead of
To have the Reverse Proxy serve the static html/javscript assets instead of
proxying them to the REST layer, register the location where you unpacked
the web application as the document root and add rewrite rules::
the web application as the document root and add a simple rewrite rule::
<Directory /usr/share/zuul>
DocumentRoot /var/lib/html
<Directory /var/lib/html>
Require all granted
</Directory>
Alias / /usr/share/zuul/
<Location />
RewriteEngine on
RewriteBase /
# Rewrite api to the zuul-web endpoint
RewriteRule api/tenant/(.*)/console-stream ws://localhost:9000/api/tenant/$1/console-stream [P,L]
RewriteRule api/(.*)$ http://localhost:9000/api/$1 [P,L]
# Backward compatible rewrite
RewriteRule t/(.*)/(.*).html(.*) /t/$1/$2$3 [R=301,L,NE]
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Location>
Sub directory serving
---------------------
The web application needs to be rebuild to update the internal location of
the static files. Set the homepage setting in the package.json to an
absolute path or url. For example, to deploy the web interface through a
'/zuul/' sub directory:
.. note::
The web dashboard source code and package.json are located in the ``web``
directory. All the yarn commands need to be executed from the ``web``
directory.
.. code-block:: bash
sed -e 's#"homepage": "/"#"homepage": "/zuul/"#' -i package.json
yarn build
Then assuming the web application is unpacked in /usr/share/zuul,
add the following rewrite rules::
<Directory /usr/share/zuul>
Require all granted
</Directory>
Alias /zuul /usr/share/zuul/
<Location /zuul>
RewriteEngine on
RewriteBase /zuul
# Rewrite api to the zuul-web endpoint
RewriteRule api/tenant/(.*)/console-stream ws://localhost:9000/api/tenant/$1/console-stream [P,L]
RewriteRule api/(.*)$ http://localhost:9000/api/$1 [P,L]
# Backward compatible rewrite
RewriteRule t/(.*)/(.*).html(.*) /t/$1/$2$3 [R=301,L,NE]
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /zuul/index.html [L]
</Location>
RewriteEngine on
RewriteRule ^/t/.*/(.*)$ /$1 [L]
RewriteRule ^/api/tenant/(.*)/console-stream ws://localhost:9000/api/tenant/$1/console-stream [P]
RewriteRule ^/api/(.*)$ http://localhost:9000/api/$1 [P]
White Labeled Tenant
--------------------
@ -200,27 +147,14 @@ rule to ensure connection webhooks don't try to get put into the tenant scope.
Assuming the zuul tenant name is "example", the rewrite rules are::
<Directory /usr/share/zuul>
DocumentRoot /var/lib/html
<Directory /var/lib/html>
Require all granted
</Directory>
Alias / /usr/share/zuul/
<Location />
RewriteEngine on
RewriteBase /
# Rewrite api to the zuul-web endpoint
RewriteRule api/connection/(.*)$ http://localhost:9000/api/connection/$1 [P,L]
RewriteRule api/console-stream ws://localhost:9000/api/tenant/example/console-stream [P,L]
RewriteRule api/(.*)$ http://localhost:9000/api/tenant/example/$1 [P,L]
# Backward compatible rewrite
RewriteRule t/(.*)/(.*).html(.*) /t/$1/$2$3 [R=301,L,NE]
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Location>
RewriteEngine on
RewriteRule ^/api/connection/(.*)$ http://localhost:9000/api/connection/$1 [P]
RewriteRule ^/api/console-stream ws://localhost:9000/api/tenant/example/console-stream [P]
RewriteRule ^/api/(.*)$ http://localhost:9000/api/tenant/example/$1 [P]
Static External
---------------
@ -231,8 +165,9 @@ Static External
dynamic url rewrite rules only works for white-labeled deployments.
In order to serve the zuul dashboard code from an external static location,
``REACT_APP_ZUUl_API`` must be set at javascript build time:
``ZUUL_API_URL`` must be set at javascript build time by passing the
``--define`` flag to the ``npm build:dist`` command.
.. code-block:: bash
REACT_APP_ZUUL_API='http://zuul-web.example.com' yarn build
npm build:dist -- --define "ZUUL_API_URL='http://zuul-web.example.com'"

+ 84
- 49
doc/source/developer/javascript.rst View File

@ -6,15 +6,9 @@ is managed using Javascript toolchains. It is intended to be served by zuul-web
directly from zuul/web/static in the simple case, or to be published to
an alternate static web location, such as an Apache server.
The web dashboard is written in `React`_ and `Patternfly`_ and is
managed by `create-react-app`_ and `yarn`_ which in turn both assume a
functioning and recent `nodejs`_ installation.
.. note::
The web dashboard source code and package.json are located in the ``web``
directory. All the yarn commands need to be executed from the ``web``
directory.
The web dashboard is written in `Typescript`_ and `Angular`_ and is
managed by `yarn`_ and `webpack`_ which in turn both assume a functioning
and recent `nodejs`_ installation.
For the impatient who don't want deal with javascript toolchains
----------------------------------------------------------------
@ -104,27 +98,28 @@ conflicts is to first resolve the conflicts, if any, in ``package.json``. Then:
Which causes yarn to discard the ``yarn.lock`` file, recalculate the
dependencies and write new content.
React Components
----------------
webpack asset management
------------------------
Each page is a React Component. For instance the status.html page code is
``web/src/pages/status.jsx``.
`webpack`_ takes care of bundling web assets for deployment, including tasks
such as minifying and transpiling for older browsers. It takes a
javascript-first approach, and generates a html file that includes the
appropriate javascript and CSS to get going.
Mapping of pages/urls to components can be found in the route list in
``web/src/routes.js``.
The main `webpack`_ config file is ``webpack.config.js``. In the Zuul tree that
file is a stub file that includes either a dev or a prod environment from
``web/config/webpack.dev.js`` or ``web/config/webpack.prod.js``. Most of the
important bits are in ``web/config/webpack.common.js``.
Here are some useful documentation about the different libraries:
Angular Components
------------------
- https://reactjs.org/docs/getting-started.html
- https://reacttraining.com/react-router/web/guides/philosophy
- https://react-bootstrap.github.io/components/forms/
- https://redux.js.org/introduction/coreconcepts
- https://www.patternfly.org/pattern-library/
- https://rawgit.com/patternfly/patternfly-react/gh-pages/
Each page has an `Angular Component`_ associated with it. For instance, the
``status.html`` page has code in ``web/status/status.component.ts`` and the
relevant HTML can be found in ``web/status/status.component.html``.
The gh-pages are built from storybook present in the patternfly-react
repository. Sometime the 'View Info' is not enough and using grep in the
repository may yield better documentation.
Mapping of pages/urls to components can be found in the routing module in
``web/app-routing.module.ts``.
Development
-----------
@ -133,43 +128,68 @@ Building the code can be done with:
.. code-block:: bash
yarn build
npm run build
zuul-web has a ``static`` route defined which serves files from
``zuul/web/static``. ``yarn build`` will put the build output files
``zuul/web/static``. ``npm run build`` will put the build output files
into the ``zuul/web/static`` directory so that zuul-web can serve them.
Development server that handles things like reloading and
hot-updating of code can be started with:
There is a also a development-oriented version of that same command:
.. code-block:: bash
npm run build:dev
which will build for the ``dev`` environment. This causes some sample data
to be bundled and included.
Webpack includes a development server that handles things like reloading and
hot-updating of code. The following:
.. code-block:: bash
npm run start
will build the code and launch the dev server on `localhost:8080`. It will
be configured to use the API endpoint from OpenStack's Zuul. The
``webpack-dev-server`` watches for changes to the files and
re-compiles/refresh as needed.
.. code-block:: bash
yarn start
npm run start:multi
will build the code and launch the dev server on `localhost:3000`. Fake
api response needs to be set in the ``web/public/api`` directory::
will do the same but will be pointed at the SoftwareFactory Project Zuul, which
is multi-tenant.
Arbitrary command line options will be passed through after a ``--`` such as:
.. code-block:: bash
mkdir public/api/
for route in info status jobs builds; do
curl -o public/api/${route} https://zuul.openstack.org/api/${route}
done
npm run start -- --open-file='status.html'
That's kind of annoying though, so additional targets exist for common tasks:
To use an existing zuul api, uses the REACT_APP_ZUUl_API environment
variable:
Run status against `basic` built-in demo data.
.. code-block:: bash
# Use openstack zuul's api:
yarn start:openstack
npm run start:basic
Run status against `openstack` built-in demo data
# Use software-factory multi-tenant zuul's api:
yarn start:multi
.. code-block:: bash
npm run start:openstack
# Use a custom zuul:
REACT_APP_ZUUL_API="https://zuul.example.com/api/" yarn start
Run status against `tree` built-in demo data.
.. code-block:: bash
npm run start:tree
Additional run commands can be added in `package.json` in the ``scripts``
section.
Deploying
---------
@ -179,16 +199,31 @@ by zuul-web from its ``static`` route. In order to make sure this works
properly, the javascript build needs to be performed so that the javascript
files are in the ``zuul/web/static`` directory. Because the javascript
build outputs into the ``zuul/web/static`` directory, as long as
``yarn build`` has been done before ``pip install .`` or
``npm run build`` has been done before ``pip install .`` or
``python setup.py sdist``, all the files will be where they need to be.
As long as `yarn`_ is installed, the installation of zuul will run
``yarn build`` appropriately.
``npm run build`` appropriately.
Debugging minified code
-----------------------
Both the ``dev`` and ``prod`` ennvironments use the same `devtool`_
called ``source-map`` which makes debugging errors easier by including mapping
information from the minified and bundled resources to their approriate
non-minified source code locations. Javascript errors in the browser as seen
in the developer console can be clicked on and the appropriate actual source
code location will be shown.
``source-map`` is considered an appropriate `devtool`_ for production, but has
the downside that it is slower to update. However, since it includes the most
complete mapping information and doesn't impact execution performance, so in
our case we use it for both.
.. _yarn: https://yarnpkg.com/en/
.. _nodejs: https://nodejs.org/
.. _webpack: https://webpack.js.org/
.. _devtool: https://webpack.js.org/configuration/devtool/#devtool
.. _nodeenv: https://pypi.org/project/nodeenv
.. _React: https://reactjs.org/
.. _Patternfly: https://www.patternfly.org/
.. _create-react-app: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md
.. _Angular: https://angular.io
.. _Angular Component: https://angular.io/guide/architecture-components
.. _Typescript: https://www.typescriptlang.org/

+ 86
- 0
package.json View File

@ -0,0 +1,86 @@
{
"name": "@zuul-ci/dashboard",
"version": "1.0.0",
"description": "Web Dashboard for Zuul",
"main": "web/main.ts",
"repository": "https://git.zuul-ci.org/zuul",
"author": "OpenStack Infra",
"license": "Apache-2.0",
"babel": {
"presets": [
"env"
]
},
"dependencies": {
"@angular/common": "^6.0.3",
"@angular/compiler": "^6.0.3",
"@angular/core": "^6.0.3",
"@angular/forms": "^6.0.3",
"@angular/platform-browser": "^6.0.3",
"@angular/platform-browser-dynamic": "^6.0.3",
"@angular/router": "^6.0.3",
"bootstrap": "3.1.1",
"core-js": "^2.5.3",
"graphitejs": "https://github.com/prestontimmons/graphitejs/archive/master.tar.gz",
"jquery": "^3.3.1",
"jquery-visibility": "https://github.com/mathiasbynens/jquery-visibility/archive/master.tar.gz",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.2.0",
"rxjs-compat": "^6.0.0-rc.0",
"zone.js": "^0.8.26"
},
"scripts": {
"build": "npm run build:dist",
"build:dev": "webpack --env=dev",
"build:dist": "webpack --env=prod",
"build:dist-with-depends": "yarn install && npm run build:dist",
"format": "tslint --project tsconfig.json -c tslint.json --fix",
"lint": "webpack --env=lint",
"start": "webpack-dev-server --env=dev --define ZUUL_API_URL=\"'https://zuul.openstack.org'\" --open-page='status.html'",
"start:multi": "webpack-dev-server --env=dev --define ZUUL_API_URL=\"'https://softwarefactory-project.io/zuul'\" --open-page='tenants.html'",
"start:basic": "webpack-dev-server --env=dev --open-page='status.html?demo=basic'",
"start:openstack": "webpack-dev-server --env=dev --open-page='status.html?demo=openstack'",
"start:tree": "webpack-dev-server --env=dev --open-page='status.html?demo=tree'"
},
"devDependencies": {
"@types/angular": "^1.6.43",
"@types/bootstrap": "^4.0.0",
"@types/core-js": "^0.9.46",
"@types/jquery": "^3.3.1",
"@types/node": "^9.4.7",
"babel-core": "^6.26.0",
"babel-eslint": "^8.0.3",
"babel-loader": "^7.1.2",
"babel-plugin-angularjs-annotate": "^0.8.2",
"babel-preset-env": "^1.6.1",
"clean-webpack-plugin": "^0.1.16",
"codelyzer": "^4.2.1",
"css-loader": "^0.28.10",
"eslint": ">=3.19.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-loader": "^2.0.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^6.0.0",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"file-loader": "^1.1.11",
"fork-ts-checker-webpack-plugin": "^0.4.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.0",
"resolve-url-loader": "^2.1.0",
"style-loader": "^0.20.3",
"ts-loader": "^4.1.0",
"ts-node": "^5.0.1",
"tslint": "^5.9.1",
"tslint-angular": "^1.1.1",
"tslint-loader": "^3.6.0",
"typescript": "2.7.2",
"url-loader": "^0.5.9",
"webpack": "^4.4.0",
"webpack-archive-plugin": "^3.0.0",
"webpack-bundle-analyzer": "^2.9.1",
"webpack-cli": "^2.0.11",
"webpack-dev-server": "^3.0.0",
"webpack-merge": "^4.1.0"
}
}

+ 21
- 0
playbooks/dashboard/multi.yaml View File

@ -0,0 +1,21 @@
- hosts: all
tasks:
- name: Make tenant subdir
file:
state: directory
dest: '{{ zuul.project.src_dir }}/{{ javascript_content_dir }}/t'
- name: Copy the html/javascript content into subdirs
shell: |
CONTENT_DIR="{{ zuul.project.src_dir }}/{{ javascript_content_dir }}"
mkdir $CONTENT_DIR/t/{{ item }}
for f in $(find $CONTENT_DIR -type f -mindepth 1 -maxdepth 1) ; do
cp $f $CONTENT_DIR/t/{{ item }}
done
with_items:
- local
- ansible
- ansible-dev
- openstack.org
- rdoproject.org

+ 13
- 14
playbooks/dashboard/run.yaml View File

@ -1,19 +1,18 @@
- hosts: all
pre_tasks:
- name: Update homepage for sub directory deployment
replace:
path: '{{ zuul.project.src_dir }}/web/package.json'
regexp: '"homepage": "/"'
replace: '"homepage": "./"'
# NOTE: using "./" is not enough to support html5 links, even with
# rewrite rules for unknown files, accessing 'job/devstack' will make
# the dashboard load static files from 'job/static/...'
# This works for the preview dashboard that can only be loaded from the
# npm/html directory anyway.
roles:
- revoke-sudo
- set-zuul-log-path-fact
# Both sets of quotes are required.
# The "" quotes are for the shell to protect the '' quotes.
# We need the '' quotes because defines here are essentially
# direct string substitutions. Therefore:
# --define "ZUUL_API_URL='https://zuul.openstack.org'"
# with the javascript code:
# return ZUUL_API_URL
# results in
# return 'https://zuul.openstack.org'
# in the compiled javascript.
- role: npm
npm_command: build
environment:
REACT_APP_ZUUL_API: "{{ zuul_api_url }}/api/"
npm_command: >-
build:dist --
--define "ZUUL_API_URL='{{ zuul_api_url }}'"

+ 0
- 11
releasenotes/notes/react-zuul-a593c7627ca22b37.yaml View File

@ -1,11 +0,0 @@
---
features:
- |
The Zuul web dashboard has been rewritten in React.
upgrade:
- |
The Zuul web dashboard is now a single index.html and static offload
server needs new rewrite rules. Check the install instruction for backward
compatible rewrite rules. Note that serving the web dashboard from a
sub-directory requires the application to be rebuilt using the desired
homepage location.

+ 2
- 2
tests/unit/test_web.py View File

@ -245,9 +245,9 @@ class TestWeb(BaseTestWeb):
self.assertEqual(1, data[0]['queue'])
def test_web_bad_url(self):
# do we redirect to index.html
# do we 404 correctly
resp = self.get_url("status/foo")
self.assertEqual(200, resp.status_code)
self.assertEqual(404, resp.status_code)
def test_web_find_change(self):
# can we filter by change id


+ 8
- 8
tests/unit/test_web_urls.py View File

@ -51,8 +51,10 @@ class TestWebURLs(ZuulTestCase):
]:
for item in page.find_all(tag):
suburl = item.get(attr)
if suburl.startswith('/'):
suburl = suburl[1:]
# Skip empty urls. Also skip the navbar relative link for now.
# TODO(mordred) Remove when we have the top navbar link sorted.
if suburl is None or suburl == "../":
continue
link = urllib.parse.urljoin(url, suburl)
self._get(self.port, link)
@ -64,8 +66,7 @@ class TestDirect(TestWebURLs):
self.port = self.web.port
def test_status_page(self):
self._crawl('/')
self._crawl('/t/tenant-one/status')
self._crawl('/t/tenant-one/status.html')
class TestWhiteLabel(TestWebURLs):
@ -80,8 +81,7 @@ class TestWhiteLabel(TestWebURLs):
self.port = self.proxy.port
def test_status_page(self):
self._crawl('/')
self._crawl('/status')
self._crawl('/status.html')
class TestWhiteLabelAPI(TestWebURLs):
@ -108,11 +108,11 @@ class TestSuburl(TestWebURLs):
def setUp(self):
super(TestSuburl, self).setUp()
rules = [
('^/zuul/(.*)$', 'http://localhost:{}/\\1'.format(
('^/zuul3/(.*)$', 'http://localhost:{}/\\1'.format(
self.web.port)),
]
self.proxy = self.useFixture(WebProxyFixture(rules))
self.port = self.proxy.port
def test_status_page(self):
self._crawl('/zuul/')
self._crawl('/zuul3/t/tenant-one/status.html')

+ 2
- 4
tools/pip.sh View File

@ -32,9 +32,7 @@ then
fi
if [[ ! -f zuul/web/static/status.html ]]
then
pushd web/
yarn install
yarn build
popd
yarn install
npm run build:dev
fi
pip install $*

+ 17
- 0
tsconfig.json View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"sourceMap": true,
"moduleResolution": "node",
"outDir": "./zuul/web/static/",
"noImplicitAny": false,
"target": "es6",
"lib": [ "es2015", "dom" ],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowJs": false
},
"include": [
"webpack.config.ts",
"web/**/*.ts"
]
}

+ 7
- 0
tslint.json View File

@ -0,0 +1,7 @@
{
"extends": ["tslint-angular"],
"rules": {
"array-type": [true, "array-simple"],
"semicolon": [true, "never"]
}
}

+ 0
- 23
web/.eslintrc View File

@ -1,23 +0,0 @@
parser: babel-eslint
plugins:
- standard
- jest
rules:
no-console: off
semi: [error, never]
quotes: [error, single]
lines-between-class-members: error
react/prop-types: error
react/jsx-key: error
react/no-did-mount-set-state: error
react/no-did-update-set-state: error
react/no-deprecated: error
extends:
- eslint:recommended
- plugin:react/recommended
settings:
react:
version: 16.4
env:
jest/globals: true
browser: true

+ 1
- 0
web/.gitignore View File

@ -0,0 +1 @@
public_html/lib

+ 1
- 0
web/.jshintignore View File

@ -0,0 +1 @@
public_html/lib

+ 21
- 0
web/.jshintrc View File

@ -0,0 +1,21 @@
{
"bitwise": true,
"eqeqeq": true,
"forin": true,
"latedef": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"undef": true,
"unused": true,
"strict": false,
"laxbreak": true,
"browser": true,
"predef": [
"jQuery",
"zuul"
]
}

+ 84
- 0
web/app-routing.module.ts View File

@ -0,0 +1,84 @@
// Routing information for Zuul dashboard pages
//
// Copyright 2018 Red Hat, 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.
import { NgModule, isDevMode } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import BuildsComponent from './builds/builds.component'
import JobsComponent from './jobs/jobs.component'
import StatusComponent from './status/status.component'
import StreamComponent from './stream/stream.component'
import TenantsComponent from './tenants/tenants.component'
// Have all routes go to builds.html for now
const appRoutes: Routes = [
{
path: 't/:tenant/builds.html',
component: BuildsComponent
},
{
path: 'builds.html',
component: BuildsComponent
},
{
path: 't/:tenant/status.html',
component: StatusComponent
},
{
path: 'status.html',
component: StatusComponent
},
{
path: 't/:tenant/jobs.html',
component: JobsComponent
},
{
path: 'jobs.html',
component: JobsComponent
},
{
path: 'stream.html',
component: StreamComponent
},
{
path: 't/:tenant/stream.html',
component: StreamComponent
},
{
path: 'tenants.html',
component: TenantsComponent
},
{
path: 't/tenants.html',
component: TenantsComponent
},
{
path: '**',
component: StatusComponent
}
]
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
// Enable router tracing in devel mode. This prints router decisions
// to the console.log.
{ enableTracing: isDevMode() }
)],
exports: [RouterModule]
})
export class AppRoutingModule { }

+ 28
- 0
web/app.component.ts View File

@ -0,0 +1,28 @@
// Main dashboard component
//
// Copyright 2018 Red Hat, 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.
import { Component } from '@angular/core'
@Component({
selector: 'zuul-dashboard',
template: `
<navigation></navigation>
<div class="container-fluid">
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent {}

+ 73
- 0
web/app.module.ts View File

@ -0,0 +1,73 @@
// Entrypoint for Zuul dashboard pages
//
// Copyright 2018 Red Hat, 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.
import './styles/zuul.css'
import { APP_BASE_HREF } from '@angular/common'
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HttpClientModule } from '@angular/common/http'
import { FormsModule } from '@angular/forms'
import { CoreModule } from './core/core.module'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { getAppBaseHref } from './zuul/zuul.service'
import BuildsComponent from './builds/builds.component'
import NavigationComponent from './navigation/navigation.component'
import JobsComponent from './jobs/jobs.component'
import StatusComponent from './status/status.component'
import StreamComponent from './stream/stream.component'
import TenantsComponent from './tenants/tenants.component'
import ZuulService from './zuul/zuul.service'
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
FormsModule,
CoreModule.forRoot({}),
AppRoutingModule,
],
declarations: [
AppComponent,
BuildsComponent,
NavigationComponent,
JobsComponent,
StatusComponent,
StreamComponent,
TenantsComponent
],
entryComponents: [
BuildsComponent,
NavigationComponent,
JobsComponent,
StatusComponent,
StreamComponent,
TenantsComponent
],
providers: [
ZuulService,
{provide: APP_BASE_HREF, useValue: getAppBaseHref()}
],
bootstrap: [
AppComponent
]
})
export class AppModule { }

+ 0
- 1
web/build View File

@ -1 +0,0 @@
../zuul/web/static/

+ 28
- 0
web/builds/build.ts View File

@ -0,0 +1,28 @@
// Copyright 2017 Red Hat
//
// 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.
export default class Build {
constructor(
public job_name: string,
public result: string,
public project: string,
public pipeline: string,
public ref_url: string,
public duration: number,
public start_time: string,
public log_url?: string,
) {}
}

+ 67
- 0
web/builds/builds.component.html View File

@ -0,0 +1,67 @@
<!--
Copyright 2017 Red Hat
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.
-->
<div class="container-fluid">
<span style="float: right; margin-top: 7px;">
<form class="form-inline" #buildsForm="ngForm">
<div class="form-group">
<label for="pipeline">Pipeline:</label>
<input class="form-control" id="pipeline"
[(ngModel)]="pipeline" name="pipeline" />
</div>
<div class="form-group">
<label for="job_name">Job:</label>
<input class="form-control" id="job_name"
[(ngModel)]="job_name" name="job_name" />
</div>
<div class="form-group">
<label for="project">Project:</label>
<input class="form-control" id="project"
[(ngModel)]="project" name="project">
</div>
<button type="submit" class="btn" (click)='buildsFetch()'>
Refresh
</button>
</form>
</span>
</div>
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Job</th>
<th>Project</th>
<th>Branch</th>
<th>Pipeline</th>
<th>Change</th>
<th>Duration</th>
<th>Log url</th>
<th>Start time</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let build of builds" [class]="getRowClass(build)">
<td>{{ build.job_name }}</td>
<td>{{ build.project }}</td>
<td>{{ build.branch }}</td>
<td>{{ build.pipeline }}</td>
<td><a href="{{ build.ref_url }}" target="_self">change</a></td>
<td>{{ build.duration }} seconds</td>
<td><a *ngIf="build.log_url" href="{{ build.log_url }}" target="_self">logs</a></td>
<td>{{ build.start_time }}</td>
<td>{{ build.result }}</td>
</tr>
</tbody>
</table>

+ 78
- 0
web/builds/builds.component.ts View File

@ -0,0 +1,78 @@
// Copyright 2017 Red Hat
//
// 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.
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/map'
import ZuulService from '../zuul/zuul.service'
import Build from './build'
@Component({
template: require('./builds.component.html')
})
export default class BuildsComponent implements OnInit {
builds: Build[]
pipeline: string
job_name: string
project: string
constructor(
private http: HttpClient, private route: ActivatedRoute,
private zuul: ZuulService
) {}
async ngOnInit() {
await this.zuul.setTenant(this.route.snapshot.paramMap.get('tenant'))
this.pipeline = this.route.snapshot.queryParamMap.get('pipeline')
this.job_name = this.route.snapshot.queryParamMap.get('job_name')
this.project = this.route.snapshot.queryParamMap.get('project')
this.buildsFetch()
}
buildsFetch(): void {
let params = new HttpParams()
if (this.pipeline) { params = params.set('pipeline', this.pipeline) }
if (this.job_name) { params = params.set('job_name', this.job_name) }
if (this.project) { params = params.set('project', this.project) }
const remoteLocation = this.zuul.getSourceUrl('builds')
if (remoteLocation) {
this.http.get<Build[]>(remoteLocation, {params: params})
.subscribe(builds => {
for (const build of builds) {
/* Fix incorect url for post_failure job */
/* TODO(mordred) Maybe let's fix this server side? */
if (build.log_url === build.job_name) {
build.log_url = undefined
}
}
this.builds = builds
})
}
}
getRowClass(build: Build): string {
if (build.result === 'SUCCESS') {
return 'success'
} else {
return 'warning'
}
}
}

+ 24
- 0
web/config/main.ejs View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<!--
Copyright 2017 Red Hat
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>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title id='pagetitle'><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<zuul-dashboard></zuul-dashboard>
</body></html>

+ 178
- 0
web/config/status-basic.json View File

@ -0,0 +1,178 @@
{
"last_reconfigured": 1389381756000,
"message": "Example info message",
"pipelines": [
{
"name": "test",
"description": "Lint and unit tests",
"change_queues": [
{
"name": "some-jobs@worker301.ci-example.org",
"heads": [
[
{
"id": "10101,1",
"url": "#!/review.example.org/r/10101",
"project": "openstack/infra/zuul",
"jobs": [
{
"name": "zuul-merge",
"url": "#!/jenkins.example.org/job/zuul-merge/201",
"result": "SUCCESS",
"voting": true
},
{
"name": "zuul-lint",
"url": "#!/jenkins.example.org/job/zuul-lint/201",
"result": "SUCCESS",
"voting": true
},
{
"name": "zuul-test",
"url": "#!/jenkins.example.org/job/zuul-test/201",
"result": "SUCCESS",
"voting": true
}
]
}
],
[
{
"id": "10103,1",
"url": "#!/review.example.org/r/10103",
"project": "google/gerrit",
"jobs": [
{
"name": "gerrit-merge",
"url": "#!/jenkins.example.org/job/gerrit-merge/203",
"result": "SUCCESS",
"voting": false
}
]
}
]
]
},
{
"name": "other-jobs@worker301.ci-example.org",
"heads": [
[
{
"id": "10102,1",
"url": "#!/review.example.org/r/10102",
"project": "google/gerrit",
"jobs": [
{
"name": "gerrit-merge",
"url": "#!/jenkins.example.org/job/gerrit-merge/202",
"result": "UNSTABLE",
"voting": false
}
]
}
],
[
{
"id": "10104,1",
"url": "#!/review.example.org/r/10104",
"project": "openstack/infra/zuul",
"jobs": [
{
"name": "zuul-merge",
"url": "#!/jenkins.example.org/job/zuul-merge/204",
"result": "SUCCESS",
"voting": true
},
{
"name": "zuul-lint",
"url": "#!/jenkins.example.org/job/zuul-lint/204",
"result": "FAILURE",
"voting": true
},
{
"name": "zuul-test",
"url": "#!/jenkins.example.org/job/zuul-test/204",
"result": null,
"voting": true
}
]
}
]
]
}
]
},
{
"name": "gate-and-submit",
"change_queues": []
},
{
"name": "postmerge",
"change_queues": [
{
"name": "some-jobs@worker301.ci-example.org",
"heads": [
[
{
"id": "7f1d65cb0f663c907698f915da01c008c7ef4748",
"url": "#!/review.example.org/r/10100",
"project": "openstack/infra/zuul",
"jobs": [
{
"name": "zuul-lint",
"url": "#!/jenkins.example.org/job/zuul-lint/200",
"result": "SUCCESS",
"voting": true
},
{
"name": "zuul-test",
"url": "#!/jenkins.example.org/job/zuul-test/200",
"result": "FAILURE",
"voting": true
},
{
"name": "zuul-regression-python2",
"url": "#!/jenkins.example.org/job/zuul-regression-python2/200",
"result": "SUCCESS",
"voting": true
},
{
"name": "zuul-regression-python3",
"url": "#!/jenkins.example.org/job/zuul-regression-python3/200",
"result": "FAILURE",
"voting": true
},
{
"name": "zuul-performance-python2",
"url": null,
"result": null,
"voting": true
},
{
"name": "zuul-performance-python3",
"url": null,
"result": null,
"voting": true
},
{
"name": "zuul-docs-publish",
"url": null,
"result": null,
"voting": true
}
]
}
]
]
}
]
}
],
"trigger_event_queue": {
"length": 0
},
"result_event_queue": {
"length": 0
},
"zuul_version": "2.0.0.19"
}

+ 312
- 0
web/config/status-openstack.json View File

@ -0,0 +1,312 @@
{
"last_reconfigured": 1389381756000,
"pipelines": [
{
"name": "check",
"description": "Newly uploaded patchsets enter this pipeline to receive an initial +/-1 Verified vote from Jenkins.",
"change_queues": [
{
"heads": [],
"name": "stackforge/tripleo-image-elements"
}
]
},
{
"description": "Changes that have been approved by core developers are enqueued in order in this pipeline, and .",
"change_queues": [
{
"heads": [],
"name": "openstack-detackforge/reddwarf-integration"
},
{
"heads": [],
"name": "stackforge/moniker"
},
{
"heads": [
[
{
"url": "https://review.openstack.org/26292",
"project": "openstack/quantum",
"jobs": [
{
"url": "https://jenkins.openstack.org/job/gate-quantum-docs/5501/consoleFull",
"voting": true,
"result": "SUCCESS",
"name": "gate-quantum-docs"
},
{
"url": "https://jenkins.openstack.org/job/gate-quantum-pep8/6254/consoleFull",
"voting": true,
"result": "SUCCESS",
"name": "gate-quantum-pep8"
},
{
"url": "https://jenkins.openstack.org/job/gate-quantum-python26/5876/",
"voting": true,
"result": null,
"name": "gate-quantum-python26"
},
{
"url": "https://jenkins.openstack.org/job/gate-quantum-python27/5887/",
"voting": true,
"result": null,
"name": "gate-quantum-python27"
},
{
"url": "https://jenkins.openstack.org/job/gate-tempest-devstack-vm-quantum/17548/",
"voting": true,
"result": null,
"name": "gate-tempest-devstack-vm-quantum"
}
],
"id": "26292,1"
}
]
],
"name": "openstack-dev/devstack, openstack-infra/devstack-gate, openstack/cinder, openstack/glance, openstack/horizon, openstack/keystone, openstack/nova, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-quantumclient, openstack/quantum, openstack/swift, openstack/tempest, z/tempest"
},
{
"heads": [],
"name": "openstack/ceilometer"
},
{
"heads": [],
"name": "stackforge/puppet-openstack"
},
{
"heads": [],
"name": "stackforge/puppet-cinder"
},
{
"heads": [],
"name": "stackforge/marconi"
},
{
"heads": [],
"name": "openstack-infra/config"
},
{
"heads": [],
"name": "stackforge/tripleo-image-elements"
},
{
"heads": [],
"name": "stackforge/kwapi"
},
{
"heads": [],
"name": "stackforge/python-reddwarfclient"
},
{
"heads": [],
"name": "stackforge/python-savannaclient"
},
{
"heads": [],
"name": "stackforge/python-monikerclient"
},
{
"heads": [],
"name": "stackforge/packstack"
},
{
"heads": [],
"name": "openstack/oslo.config"
},
{
"heads": [],
"name": "openstack-infra/jenkins-job-builder"
},
{
"heads": [],
"name": "stackforge/puppet-horizon"
},
{
"heads": [],
"name": "openstack/heat-cfntools"
},
{
"heads": [],
"name": "openstack/oslo-incubator"
},
{
"heads": [],
"name": "stackforge/os-config-applier"
},
{
"heads": [],
"name": "openstack/requirements"
},
{
"heads": [],
"name": "stackforge/puppet-glance"
},
{
"heads": [],
"name": "openstack-infra/gearman-plugin"
},
{
"heads": [],
"name": "stackforge/puppet-keystone"
},
{
"heads": [],
"name": "stackforge/puppet-nova"
},
{
"heads": [],
"name": "stackforge/climate"
},
{
"heads": [],
"name": "openstack/python-swiftclient"
},
{
"heads": [],
"name": "openstack/python-ceilometerclient"
},
{
"heads": [],
"name": "openstack-infra/git-review"
},
{
"heads": [],
"name": "stackforge/bufunfa"
},
{
"heads": [],
"name": "stackforge/puppet-swift"
},
{
"heads": [],
"name": "openstack-infra/statusbot"
},
{
"heads": [],
"name": "openstack/openstack-planet"
},
{
"heads": [],
"name": "openstack/python-openstackclient"
},
{
"heads": [],
"name": "stackforge/diskimage-builder"
},
{
"heads": [],
"name": "openstack-infra/gerritlib"
},
{
"heads": [],
"name": "openstack-infra/zuul"
},
{
"heads": [],
"name": "stackforge/reddwarf"
},
{
"heads": [],
"name": "openstack-dev/hacking"
},
{
"heads": [],
"name": "openstack/python-heatclient"
},
{
"heads": [],
"name": "stackforge/python-libraclient"
},
{
"heads": [],
"name": "openstack-infra/reviewday"
},
{
"heads": [],
"name": "openstack-infra/jeepyb"
},
{
"heads": [],
"name": "openstack/heat"
},
{
"heads": [],
"name": "stackforge/libra"
},
{
"heads": [],
"name": "openstack-infra/gerrit"
},
{
"heads": [],
"name": "stackforge/healthnmon"
},
{
"heads": [],
"name": "openstack-infra/gerritbot"
},
{
"heads": [],
"name": "openstack-dev/pbr"
},
{
"heads": [],
"name": "stackforge/savanna"
},
{
"heads": [],
"name": "openstack/openstack-manuals"
}
],
"name": "gate"
},
{
"description": "This pipeline runs jobs that operate after each change is merged.",
"change_queues": [
{
"heads": [],
"name": "openstack-dev/hacking, openstack-dev/openstack-qa, openstack-dev/pbr, openstack-infra/config, openstack-infra/gearman-plugin, openstack-infra/gerrit, openstack-infra/gerritbot, openstack-infra/git-review, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/api-site, openstack/ceilometer, openstack/cinder, openstack/compute-api, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/identity-api, openstack/image-api, openstack/keystone, openstack/netconn-api, openstack/nova, openstack/object-api, openstack/openstack-manuals, openstack/oslo-incubator, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/requirements, openstack/swift, openstack/volume-api, stackforge/bufunfa, stackforge/diskimage-builder, stackforge/moniker, stackforge/os-config-applier, stackforge/python-monikerclient, stackforge/python-savannaclient, stackforge/reddwarf, stackforge/savanna, stackforge/tripleo-image-elements"
}
],
"name": "post"
},
{
"description": "This pipeline runs jobs on projects in response to pre-release tags.",
"change_queues": [
{
"heads": [],
"name": "openstack-dev/hacking, openstack-dev/pbr, openstack-infra/gerritbot, openstack-infra/gerritlib, openstack-infra/git-review, openstack-infra/jeepyb, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/ceilometer, openstack/cinder, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/keystone, openstack/nova, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/swift, stackforge/moniker, stackforge/python-monikerclient, stackforge/python-reddwarfclient, stackforge/python-savannaclient, stackforge/savanna"
}
],
"name": "pre-release"
},
{
"description": "When a commit is tagged as a release, this pipeline runs jobs that publish archives and documentation.",
"change_queues": [
{
"heads": [],
"name": "openstack-dev/hacking, openstack-dev/openstack-qa, openstack-dev/pbr, openstack-infra/gerritbot, openstack-infra/gerritlib, openstack-infra/git-review, openstack-infra/jeepyb, openstack-infra/jenkins-job-builder, openstack-infra/nose-html-output, openstack-infra/reviewday, openstack-infra/statusbot, openstack-infra/zuul, openstack/ceilometer, openstack/cinder, openstack/glance, openstack/heat, openstack/heat-cfntools, openstack/horizon, openstack/keystone, openstack/nova, openstack/oslo-incubator, openstack/oslo.config, openstack/python-ceilometerclient, openstack/python-cinderclient, openstack/python-glanceclient, openstack/python-heatclient, openstack/python-keystoneclient, openstack/python-novaclient, openstack/python-openstackclient, openstack/python-quantumclient, openstack/python-swiftclient, openstack/quantum, openstack/swift, stackforge/moniker, stackforge/python-monikerclient, stackforge/python-reddwarfclient, stackforge/python-savannaclient, stackforge/savanna"
}
],
"name": "release"
},
{
"description": "This pipeline is used for silently testing new jobs.",
"change_queues": [
{
"heads": [],
"name": ""
}
],
"name": "silent"
}
],
"trigger_event_queue": {
"length": 0
},
"result_event_queue": {
"length": 0
},
"zuul_version": "2.0.0.19"
}

+ 1
- 0
web/config/status-tree.json
File diff suppressed because it is too large
View File


+ 147
- 0
web/config/webpack.common.js View File

@ -0,0 +1,147 @@
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')