Browse Source

Revert "Revert "web: rewrite interface in react""

This reverts commit 3dba813c64.

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

+ 0
- 8
.babelrc View File

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

+ 0
- 7
.eslintrc View File

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

+ 18
- 23
.zuul.yaml View File

@ -42,27 +42,20 @@
- job:
name: zuul-build-dashboard
parent: build-javascript-content
success-url: 'npm/html/status.html'
success-url: 'npm/html/'
files:
- package.json
- tsconfig.json
- tslint.json
- web/.*
- webpack.config.js
- yarn.lock
vars:
javascript_content_dir: zuul/web/static
javascript_content_dir: "../zuul/web/static"
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
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:
@ -82,15 +75,15 @@
- zuul-build-dashboard-multi-tenant
- nodejs-npm-run-lint:
vars:
node_version: 8
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:
@ -114,15 +107,15 @@
- zuul-build-dashboard
- nodejs-npm-run-lint:
vars:
node_version: 8
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:
@ -134,7 +127,9 @@
- publish-openstack-python-branch-tarball
- publish-openstack-javascript-content:
vars:
node_version: 8
node_version: 8
zuul_work_dir: "{{ zuul.project.src_dir }}/web"
create_tarball_directory: build
- openstackzuul-pbrx-push-container-images:
vars:
pbrx_prefix: zuul


+ 1
- 0
MANIFEST.in View File

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


+ 5
- 1
TESTING.rst View File

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


+ 83
- 18
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/zuul3/ is an example of a Zuul dashboard
https://softwarefactory-project.io/zuul/ 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,18 +121,71 @@ simplest reverse-proxy case is::
Static Offload
--------------
To have the Reverse Proxy serve the static html/javscript assets instead of
To have the Reverse Proxy serve the static html/javascript assets instead of
proxying them to the REST layer, register the location where you unpacked
the web application as the document root and add a simple rewrite rule::
the web application as the document root and add rewrite rules::
DocumentRoot /var/lib/html
<Directory /var/lib/html>
<Directory /usr/share/zuul>
Require all granted
</Directory>
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]
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>
White Labeled Tenant
--------------------
@ -147,14 +200,27 @@ 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::
DocumentRoot /var/lib/html
<Directory /var/lib/html>
<Directory /usr/share/zuul>
Require all granted
</Directory>
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]
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>
Static External
---------------
@ -165,9 +231,8 @@ 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,
``ZUUL_API_URL`` must be set at javascript build time by passing the
``--define`` flag to the ``npm build:dist`` command.
``REACT_APP_ZUUl_API`` must be set at javascript build time:
.. code-block:: bash
npm build:dist -- --define "ZUUL_API_URL='http://zuul-web.example.com'"
REACT_APP_ZUUL_API='http://zuul-web.example.com' yarn build

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

@ -6,9 +6,15 @@ 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 `Typescript`_ and `Angular`_ and is
managed by `yarn`_ and `webpack`_ which in turn both assume a functioning
and recent `nodejs`_ installation.
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.
For the impatient who don't want deal with javascript toolchains
----------------------------------------------------------------
@ -98,28 +104,27 @@ 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.
webpack asset management
------------------------
React Components
----------------
`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.
Each page is a React Component. For instance the status.html page code is
``web/src/pages/status.jsx``.
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``.
Mapping of pages/urls to components can be found in the route list in
``web/src/routes.js``.
Angular Components
------------------
Here are some useful documentation about the different libraries:
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``.
- 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/
Mapping of pages/urls to components can be found in the routing module in
``web/app-routing.module.ts``.
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.
Development
-----------
@ -128,68 +133,43 @@ Building the code can be done with:
.. code-block:: bash
npm run build
yarn build
zuul-web has a ``static`` route defined which serves files from
``zuul/web/static``. ``npm run build`` will put the build output files
``zuul/web/static``. ``yarn build`` will put the build output files
into the ``zuul/web/static`` directory so that zuul-web can serve them.
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.
Development server that handles things like reloading and
hot-updating of code can be started with:
.. code-block:: bash
npm run start:multi
yarn start
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:
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::
.. code-block:: bash
npm run start -- --open-file='status.html'
That's kind of annoying though, so additional targets exist for common tasks:
mkdir public/api/
for route in info status jobs builds; do
curl -o public/api/${route} https://zuul.openstack.org/api/${route}
done
Run status against `basic` built-in demo data.
To use an existing zuul api, uses the REACT_APP_ZUUl_API environment
variable:
.. code-block:: bash
npm run start:basic
Run status against `openstack` built-in demo data
# Use openstack zuul's api:
yarn start:openstack
.. code-block:: bash
npm run start:openstack
# Use software-factory multi-tenant zuul's api:
yarn start:multi
Run status against `tree` built-in demo data.
# Use a custom zuul:
REACT_APP_ZUUL_API="https://zuul.example.com/api/" yarn start
.. code-block:: bash
npm run start:tree
Additional run commands can be added in `package.json` in the ``scripts``
section.
Deploying
---------
@ -199,31 +179,16 @@ 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
``npm run build`` has been done before ``pip install .`` or
``yarn 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
``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 build`` appropriately.
.. _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
.. _Angular: https://angular.io
.. _Angular Component: https://angular.io/guide/architecture-components
.. _Typescript: https://www.typescriptlang.org/
.. _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

+ 0
- 86
package.json View File

@ -1,86 +0,0 @@
{
"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"
}
}

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

@ -1,21 +0,0 @@
- 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

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

@ -1,18 +1,19 @@
- 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:dist --
--define "ZUUL_API_URL='{{ zuul_api_url }}'"
npm_command: build
environment:
REACT_APP_ZUUL_API: "{{ zuul_api_url }}/api/"

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

@ -0,0 +1,11 @@
---
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 404 correctly
# do we redirect to index.html
resp = self.get_url("status/foo")
self.assertEqual(404, resp.status_code)
self.assertEqual(200, 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,10 +51,8 @@ class TestWebURLs(ZuulTestCase):
]:
for item in page.find_all(tag):
suburl = item.get(attr)
# 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
if suburl.startswith('/'):
suburl = suburl[1:]
link = urllib.parse.urljoin(url, suburl)
self._get(self.port, link)
@ -66,7 +64,8 @@ class TestDirect(TestWebURLs):
self.port = self.web.port
def test_status_page(self):
self._crawl('/t/tenant-one/status.html')
self._crawl('/')
self._crawl('/t/tenant-one/status')
class TestWhiteLabel(TestWebURLs):
@ -81,7 +80,8 @@ class TestWhiteLabel(TestWebURLs):
self.port = self.proxy.port
def test_status_page(self):
self._crawl('/status.html')
self._crawl('/')
self._crawl('/status')
class TestWhiteLabelAPI(TestWebURLs):
@ -108,11 +108,11 @@ class TestSuburl(TestWebURLs):
def setUp(self):
super(TestSuburl, self).setUp()
rules = [
('^/zuul3/(.*)$', 'http://localhost:{}/\\1'.format(
('^/zuul/(.*)$', '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('/zuul3/t/tenant-one/status.html')
self._crawl('/zuul/')

+ 4
- 2
tools/pip.sh View File

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

+ 0
- 17
tsconfig.json View File

@ -1,17 +0,0 @@
{
"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"
]
}

+ 0
- 7
tslint.json View File

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

+ 23
- 0
web/.eslintrc View File

@ -0,0 +1,23 @@
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

+ 0
- 1
web/.gitignore View File

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

+ 0
- 1
web/.jshintignore View File

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

+ 0
- 21
web/.jshintrc View File

@ -1,21 +0,0 @@
{
"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"
]
}

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

@ -1,84 +0,0 @@
// 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 { }

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

@ -1,28 +0,0 @@
// 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 {}

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

@ -1,73 +0,0 @@
// 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 { }

+ 1
- 0
web/build View File

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

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

@ -1,28 +0,0 @@
// 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,
) {}
}

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

@ -1,67 +0,0 @@
<!--
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>

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

@ -1,78 +0,0 @@
// 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'
}
}
}

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

@ -1,24 +0,0 @@
<!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>

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

@ -1,178 +0,0 @@
{
"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"
}

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

@ -1,312 +0,0 @@
{
"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": ""