Retire releasestatus
releasestatus is not used since December 2015, see https://review.openstack.org/#/c/254817/ We can retire this repo. Depends-On: https://review.openstack.org/597370 Change-Id: I3da24845ec9634da56315d3919bd11a4bc280842
|
@ -1,6 +0,0 @@
|
|||
*.pyc
|
||||
*.swo
|
||||
*.swp
|
||||
*~
|
||||
*.yaml
|
||||
static/index.html
|
176
LICENSE
|
@ -1,176 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
38
README.rst
|
@ -1,32 +1,10 @@
|
|||
ReleaseStatus page generator
|
||||
============================
|
||||
This project is no longer maintained.
|
||||
|
||||
The releasestatus.py script is used to extract data from Launchpad
|
||||
and Gerrit and produce static HTML that shows where we are in the
|
||||
current release cycle.
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
You'll need the following Python modules installed:
|
||||
- launchpadlib
|
||||
- jinja2
|
||||
- yaml
|
||||
|
||||
You'll also need a valid SSH key for accessing Gerrit via SSH
|
||||
installed in ~/.gerritssh/id_rsa.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
python releasestatus.py grizzly.yaml > static/index.html
|
||||
|
||||
It may take a few minutes to run, depending on the number of
|
||||
projects and how many blueprints they contain.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The YAML configuration file describes the series and projects
|
||||
you want to generate data for. See comments in the example file
|
||||
releasestatus.yaml.sample for details.
|
||||
For any further questions, please email
|
||||
openstack-dev@lists.openstack.org or join #openstack-dev on
|
||||
Freenode.
|
||||
|
|
251
releasestatus.py
|
@ -1,251 +0,0 @@
|
|||
# Copyright 2011 Thierry Carrez <thierry@openstack.org>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from launchpadlib.launchpad import Launchpad
|
||||
from datetime import date, datetime
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
|
||||
class GerritReviews():
|
||||
def __init__(self, products):
|
||||
self.products = products
|
||||
self.under_review = self._get_from_gerrit('status:open')
|
||||
self.merged = self._get_from_gerrit('status:merged')
|
||||
|
||||
def _get_from_gerrit(self, *query):
|
||||
chg = {}
|
||||
age = '2mon'
|
||||
host = "review.openstack.org"
|
||||
port = "29418"
|
||||
|
||||
base_cmd = ['/usr/bin/ssh', '-p', port, host, 'gerrit', 'query',
|
||||
'--format=JSON', 'branch:master', 'AND', 'NOT',
|
||||
'age:%s' % age] + list(query)
|
||||
|
||||
for product in self.products:
|
||||
chg[product] = []
|
||||
prod_cmd = base_cmd + ['AND', 'project:openstack/%s' % product]
|
||||
sortkey = None
|
||||
|
||||
while True:
|
||||
if sortkey:
|
||||
cmd = prod_cmd + ['AND', 'resume_sortkey:%s' % sortkey]
|
||||
else:
|
||||
cmd = prod_cmd
|
||||
|
||||
proc = subprocess.Popen(cmd, bufsize=1, stdin=None,
|
||||
stdout=subprocess.PIPE, stderr=None)
|
||||
|
||||
end_of_changes = False
|
||||
for line in proc.stdout:
|
||||
data = json.loads(line)
|
||||
if 'rowCount' in data:
|
||||
if data['rowCount'] == 0:
|
||||
end_of_changes = True
|
||||
break
|
||||
else:
|
||||
break
|
||||
if data in chg[product]:
|
||||
end_of_changes = True
|
||||
break
|
||||
sortkey = data['sortKey']
|
||||
chg[product].append(data)
|
||||
if end_of_changes:
|
||||
break
|
||||
return chg
|
||||
|
||||
|
||||
class BlueprintReview():
|
||||
def __init__(self, link, image):
|
||||
self.url = link['url']
|
||||
self.subject = link['subject']
|
||||
self.image = image
|
||||
|
||||
|
||||
class ExtendedBlueprint():
|
||||
priorities = ('Essential', 'High', 'Medium', 'Low', 'Undefined', 'Not')
|
||||
|
||||
implementations = ('Implemented', 'Deployment', 'Needs Code Review',
|
||||
'Beta Available', 'Good progress', 'Slow progress',
|
||||
'Blocked', 'Needs Infrastructure', 'Started',
|
||||
'Not started', 'Unknown', 'Deferred', 'Informational')
|
||||
|
||||
def __init__(self, lbp):
|
||||
self.name = lbp.name
|
||||
self.pname = lbp.target.name
|
||||
self.whiteboard = lbp.whiteboard
|
||||
self.priority = lbp.priority
|
||||
self.implementation = lbp.implementation_status
|
||||
if lbp.milestone:
|
||||
self.milestonename = lbp.milestone.name
|
||||
self.milestonedate = lbp.milestone.date_targeted or '2099-12-30'
|
||||
self.milestonelink = lbp.milestone.web_link
|
||||
else:
|
||||
self.milestonename = ''
|
||||
self.milestonedate = '2099-12-31'
|
||||
self.milestonelink = ''
|
||||
self.implementationindex = self.implementations.index(
|
||||
self.implementation)
|
||||
self.priorityindex = self.priorities.index(self.priority)
|
||||
self.reviews = []
|
||||
self.assignee = lbp.assignee
|
||||
if (self.assignee is None):
|
||||
self.drafter = lbp.drafter
|
||||
if self.drafter is None:
|
||||
self.assigneename = ''
|
||||
self.assigneedisplay = ''
|
||||
else:
|
||||
self.assigneename = self.drafter.name
|
||||
try:
|
||||
self.assigneedisplay = str(self.drafter.display_name)
|
||||
except UnicodeEncodeError:
|
||||
self.assigneedisplay = self.drafter.name
|
||||
self.assigneedisplay = '<i>%s</i>' % self.assigneedisplay
|
||||
else:
|
||||
self.assigneename = self.assignee.name
|
||||
try:
|
||||
self.assigneedisplay = str(self.assignee.display_name)
|
||||
except UnicodeEncodeError:
|
||||
self.assigneedisplay = self.assignee.name
|
||||
|
||||
def grab_xtra_info(self, gerritreviews):
|
||||
if self.whiteboard:
|
||||
matches = re.findall(
|
||||
r'Addressed by: https://review.openstack.org/(\d+)',
|
||||
bp.whiteboard)
|
||||
self.reviews.extend(self.grab_links(matches,
|
||||
gerritreviews.merged, "MERGED"))
|
||||
self.reviews.extend(self.grab_links(matches,
|
||||
gerritreviews.under_review,
|
||||
"NEEDSREVIEW"))
|
||||
|
||||
self.impl_warn = ''
|
||||
self.impl_error = ''
|
||||
self.assignee_warn = ''
|
||||
self.assignee_error = ''
|
||||
|
||||
# Design is not approved
|
||||
#if (bp.definition_status != "Approved"):
|
||||
# impl_warn += '- Design not approved '
|
||||
|
||||
# Spec is "Needs review" but has no branch up for review
|
||||
if (self.implementation == 'Needs Code Review'
|
||||
and len(self.reviews) == 0):
|
||||
self.impl_warn += '- Topic missing on reviews ? '
|
||||
|
||||
# Spec isn't started but has branch merge proposal
|
||||
if (len(self.reviews) > 0 and (self.implementationindex > 8)):
|
||||
self.impl_warn += '- Spec has branch, should be started '
|
||||
|
||||
# Spec has "Unknown" delivery status
|
||||
if (self.implementation == 'Unknown'):
|
||||
self.impl_error += '- Status needs to be set '
|
||||
|
||||
# Assignee should not be a group
|
||||
if (self.assignee is None):
|
||||
if self.drafter is None:
|
||||
self.assignee_error += '- No assignee or drafter '
|
||||
else:
|
||||
self.assignee_warn += '- No assignee yet '
|
||||
else:
|
||||
if (self.assignee.is_team):
|
||||
self.assignee_warn += '- Should be assigned to an individual '
|
||||
|
||||
def grab_links(self, matches, changes, image):
|
||||
links = {}
|
||||
if self.pname in changes:
|
||||
for change in changes[self.pname]:
|
||||
if (change['number'] in matches or
|
||||
('topic' in changes and
|
||||
change['topic'].split("/")[-1] == bp.name)):
|
||||
links[int(change['number'])] = change
|
||||
reviews = []
|
||||
for num in sorted(links.keys()):
|
||||
reviews.append(BlueprintReview(links[num], image))
|
||||
return reviews
|
||||
|
||||
|
||||
class ExtendedBlueprintSet():
|
||||
def __init__(self, includelinks=False, reviews=None):
|
||||
self.bps = []
|
||||
self.includelinks = includelinks
|
||||
self.reviews = reviews
|
||||
|
||||
def add(self, bp):
|
||||
newebp = ExtendedBlueprint(bp)
|
||||
if self.includelinks:
|
||||
newebp.grab_xtra_info(self.reviews)
|
||||
self.bps.append(newebp)
|
||||
|
||||
|
||||
class CycleGaugeData(object):
|
||||
def __init__(self, config):
|
||||
self.ticks = ''
|
||||
self.end = -7
|
||||
for milestone in config['milestones']:
|
||||
self.ticks += ("''," * milestone[0])
|
||||
self.ticks += ("'%s'," % milestone[1])
|
||||
self.end += ((milestone[0] + 1) * 7)
|
||||
self.red = self.end - (config['milestones'][-1][0] + 1) * 7
|
||||
self.yellow = self.red - (config['milestones'][-2][0] + 1) * 7
|
||||
self.green = self.yellow - (config['milestones'][-3][0] + 1) * 7
|
||||
delta = config['releasedate'] - date.today()
|
||||
self.progress = self.end - delta.days
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
template_dir = os.path.dirname(sys.argv[0])
|
||||
if len(sys.argv) < 2:
|
||||
print >> sys.stderr, "Usage: %s config.yaml" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
with open(sys.argv[1]) as f:
|
||||
config = yaml.load(f)
|
||||
|
||||
gaugedata = CycleGaugeData(config)
|
||||
|
||||
env = Environment(loader=FileSystemLoader(template_dir))
|
||||
template = env.get_template('template.html')
|
||||
|
||||
# Get changes from Gerrit
|
||||
reviews = GerritReviews(config['products'])
|
||||
|
||||
# Log into LP
|
||||
lp = Launchpad.login_anonymously('releasestatus', 'production',
|
||||
'~/.launchpadlib-cache', version='devel')
|
||||
|
||||
# Get the blueprints
|
||||
activebps = ExtendedBlueprintSet(includelinks=True, reviews=reviews)
|
||||
pastbps = ExtendedBlueprintSet(reviews=reviews)
|
||||
for p in config['products']:
|
||||
for bp in lp.projects[p].getSeries(
|
||||
name=config['series']).valid_specifications:
|
||||
if bp.implementation_status == 'Implemented':
|
||||
pastbps.add(bp)
|
||||
else:
|
||||
activebps.add(bp)
|
||||
|
||||
print template.render(series=config['series'],
|
||||
gaugedata=gaugedata,
|
||||
date=str(datetime.utcnow()),
|
||||
activebps=activebps.bps,
|
||||
pastbps=pastbps.bps)
|
|
@ -1,24 +0,0 @@
|
|||
# Name of the series
|
||||
series: grizzly
|
||||
|
||||
# Final release date
|
||||
releasedate: 2013-04-04
|
||||
|
||||
# Short milestone codes, with number of weeks leading to them
|
||||
# The last one should be the release date
|
||||
milestones:
|
||||
- [5, g1]
|
||||
- [6, g2]
|
||||
- [5, g3]
|
||||
- [5, Apr 4]
|
||||
|
||||
# Set of projects to consider in the report
|
||||
products:
|
||||
- nova
|
||||
- glance
|
||||
- swift
|
||||
- keystone
|
||||
- horizon
|
||||
- quantum
|
||||
- cinder
|
||||
- oslo
|
BIN
static/alert.png
Before Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 91 B |
BIN
static/arrowDown
Before Width: | Height: | Size: 292 B |
BIN
static/arrowUp
Before Width: | Height: | Size: 297 B |
BIN
static/bmp.png
Before Width: | Height: | Size: 435 B |
Before Width: | Height: | Size: 397 B |
Before Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 415 B |
BIN
static/error.png
Before Width: | Height: | Size: 431 B |
|
@ -1,45 +0,0 @@
|
|||
// sorttable/sorttable-min.js
|
||||
|
||||
var SORT_COLUMN_INDEX;var arrowUp="arrowUp";var arrowDown="arrowDown";var arrowBlank="arrowBlank";function trim(str){return str.replace(/^\s*|\s*$/g,"");}
|
||||
function sortables_init(){if(!document.getElementsByTagName)return;tbls=document.getElementsByTagName("table");for(ti=0;ti<tbls.length;ti++){thisTbl=tbls[ti];if(((' '+thisTbl.className+' ').indexOf(" sortable ")!=-1)&&(thisTbl.id)){ts_makeSortable(thisTbl);}}}
|
||||
function ts_makeSortable(table){if(table.tHead&&table.tHead.rows&&table.tHead.rows.length>0){var firstRow=table.tHead.rows[0];}else if(table.rows&&table.rows.length>0){var firstRow=table.rows[0];}
|
||||
if(!firstRow)return;for(var i=0;i<firstRow.cells.length;i++){var cell=firstRow.cells[i];var txt=ts_getInnerText(cell);cell.innerHTML='<a href="#" class="sortheader" onclick="ts_resortTable(this); return false;">'
|
||||
+txt+'<img class="sortarrow" src="'+arrowBlank+'" height="6" width="9"></a>';}
|
||||
for(var i=0;i<firstRow.cells.length;i++){var cell=firstRow.cells[i];var lnk=ts_firstChildByName(cell,'A');var img=ts_firstChildByName(lnk,'IMG')
|
||||
if((' '+cell.className+' ').indexOf(" default-sort ")!=-1){ts_arrowDown(img);}
|
||||
if((' '+cell.className+' ').indexOf(" default-revsort ")!=-1){ts_arrowUp(img);}
|
||||
if((' '+cell.className+' ').indexOf(" initial-sort ")!=-1){ts_resortTable(lnk);}}}
|
||||
function ts_getInnerText(el){if(typeof el=="string")return el;if(typeof el=="undefined"){return el};/*if(el.innerText)return el.innerText*/;var str="";var cs=el.childNodes;var l=cs.length;for(var i=0;i<l;i++){node=cs[i];switch(node.nodeType){case 1:if(node.className=="sortkey"){return ts_getInnerText(node);}else if(node.className=="revsortkey"){return"-"+ts_getInnerText(node);}else{str+=ts_getInnerText(node);break;}
|
||||
case 3:str+=node.nodeValue;break;}}
|
||||
return str;}
|
||||
function ts_firstChildByName(el,name){for(var ci=0;ci<el.childNodes.length;ci++){if(el.childNodes[ci].tagName&&el.childNodes[ci].tagName.toLowerCase()==name.toLowerCase())
|
||||
return el.childNodes[ci];}}
|
||||
function ts_arrowUp(img){img.setAttribute('sortdir','up');img.src=arrowUp;}
|
||||
function ts_arrowDown(img){img.setAttribute('sortdir','down');img.src=arrowDown;}
|
||||
function ts_resortTable(lnk){var img=ts_firstChildByName(lnk,'IMG')
|
||||
var td=lnk.parentNode;var column=td.cellIndex;var table=getParent(td,'TABLE');if(table.rows.length<=1)return;SORT_COLUMN_INDEX=column;while(td.previousSibling!=null){td=td.previousSibling;if(td.nodeType!=1){continue}
|
||||
colspan=td.getAttribute("colspan");if(colspan){SORT_COLUMN_INDEX+=parseInt(colspan)-1;}}
|
||||
var itm=ts_getInnerText(table.rows[1].cells[SORT_COLUMN_INDEX]);itm=trim(itm);sortfn=ts_sort_caseinsensitive;if(itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/))sortfn=ts_sort_date;if(itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/))sortfn=ts_sort_date;if(itm.match(/^[£$]/))sortfn=ts_sort_currency;if(itm.match(/^-?[\d\.]+$/))sortfn=ts_sort_numeric;var firstRow=new Array();var newRows=new Array();for(i=0;i<table.rows[0].length;i++){firstRow[i]=table.rows[0][i];}
|
||||
for(j=1;j<table.rows.length;j++){newRows[j-1]=table.rows[j];newRows[j-1].oldPosition=j-1;}
|
||||
newRows.sort(ts_stableSort(sortfn));if(img.getAttribute("sortdir")=='down'){newRows.reverse();ts_arrowUp(img);}else{ts_arrowDown(img);}
|
||||
for(i=0;i<newRows.length;i++){if(!newRows[i].className||(newRows[i].className&&(newRows[i].className.indexOf('sortbottom')==-1)))
|
||||
table.tBodies[0].appendChild(newRows[i]);}
|
||||
for(i=0;i<newRows.length;i++){if(newRows[i].className&&(newRows[i].className.indexOf('sortbottom')!=-1))
|
||||
table.tBodies[0].appendChild(newRows[i]);}
|
||||
var allimgs=document.getElementsByTagName("img");for(var ci=0;ci<allimgs.length;ci++){var one_img=allimgs[ci];if(one_img!=img&&one_img.className=='sortarrow'&&getParent(one_img,"table")==getParent(lnk,"table")){one_img.src=arrowBlank;one_img.setAttribute('sortdir','');}}}
|
||||
function getParent(el,pTagName){if(el==null)
|
||||
return null;else if(el.nodeType==1&&el.tagName.toLowerCase()==pTagName.toLowerCase())
|
||||
return el;else
|
||||
return getParent(el.parentNode,pTagName);}
|
||||
function ts_stableSort(sortfn){function stableSort(a,b){var cmp=sortfn(a,b);if(cmp!=0){return cmp;}else{return a.oldPosition-b.oldPosition;}}
|
||||
return stableSort;}
|
||||
function ts_sort_date(a,b){aa=trim(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));bb=trim(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));if(aa.length==10){dt1=aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);}else{yr=aa.substr(6,2);if(parseInt(yr)<50){yr='20'+yr;}else{yr='19'+yr;}
|
||||
dt1=yr+aa.substr(3,2)+aa.substr(0,2);}
|
||||
if(bb.length==10){dt2=bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);}else{yr=bb.substr(6,2);if(parseInt(yr)<50){yr='20'+yr;}else{yr='19'+yr;}
|
||||
dt2=yr+bb.substr(3,2)+bb.substr(0,2);}
|
||||
if(dt1==dt2)return 0;if(dt1<dt2)return-1;return 1;}
|
||||
function ts_sort_currency(a,b){aa=ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');bb=ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');return parseFloat(aa)-parseFloat(bb);}
|
||||
function ts_sort_numeric(a,b){aa=parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));if(isNaN(aa))aa=0;bb=parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));if(isNaN(bb))bb=0;return aa-bb;}
|
||||
function ts_sort_caseinsensitive(a,b){aa=ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();bb=ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();if(aa==bb)return 0;if(aa<bb)return-1;return 1;}
|
||||
function ts_sort_default(a,b){aa=ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);bb=ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);if(aa==bb)return 0;if(aa<bb)return-1;return 1;}
|
||||
function addEvent(elm,evType,fn,useCapture){if(elm.addEventListener){elm.addEventListener(evType,fn,useCapture);return true;}else if(elm.attachEvent){var r=elm.attachEvent("on"+evType,fn);return r;}else{alert("Handler could not be removed");}}
|
282
template.html
|
@ -1,282 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html dir="ltr" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf8" http-equiv="Content-Type"/>
|
||||
<base href="."/>
|
||||
<title>
|
||||
{{ series|capitalize }} release status
|
||||
</title>
|
||||
<link href="https://blueprints.launchpad.net/@@/launchpad.png" rel="shortcut icon"/>
|
||||
<script src="http://status.openstack.org/common.js" type="text/javascript">
|
||||
</script>
|
||||
<link href="http://fonts.googleapis.com/css?family=PT+Sans&subset=latin" rel="stylesheet" type="text/css"/>
|
||||
<link href="http://www.openstack.org/themes/openstack/css/blueprint/screen.css" media="screen, projection" rel="stylesheet" type="text/css"/>
|
||||
<link href="http://www.openstack.org/themes/openstack/css/blueprint/print.css" media="print" rel="stylesheet" type="text/css"/>
|
||||
<link href="http://www.openstack.org/themes/openstack/css/main.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="combo.css" media="screen,print" rel="stylesheet" type="text/css"/>
|
||||
<script src="sorting.js" type="text/javascript">
|
||||
</script>
|
||||
<script src="https://www.google.com/jsapi" type="text/javascript">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
google.load('visualization', '1', {packages:['gauge']});
|
||||
google.setOnLoadCallback(drawChart);
|
||||
function drawChart() {
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Label');
|
||||
data.addColumn('number', 'Value');
|
||||
data.addRows(1);
|
||||
data.setValue(0, 0, '');
|
||||
data.setValue(0, 1, {{ gaugedata.progress }});
|
||||
var chart = new google.visualization.Gauge(
|
||||
document.getElementById('chart_div'));
|
||||
var options = {width: 140, height: 140,
|
||||
greenFrom: {{ gaugedata.green }}, greenTo: {{ gaugedata.yellow }},
|
||||
yellowFrom: {{ gaugedata.yellow }}, yellowTo: {{ gaugedata.red }},
|
||||
redFrom: {{ gaugedata.red }}, redTo: {{ gaugedata.end }},
|
||||
majorTicks: [ {{ gaugedata.ticks }} ],
|
||||
minorTicks: 0, max: {{ gaugedata.end}} };
|
||||
chart.draw(data, options);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="document">
|
||||
<script type="text/javascript">
|
||||
header('Release');
|
||||
</script>
|
||||
<div class="container">
|
||||
<div class="span-20">
|
||||
<h1>
|
||||
OpenStack roadmap for {{ series }}
|
||||
</h1>
|
||||
<a href="https://wiki.openstack.org/wiki/{{ series|capitalize }}_Release_Schedule">
|
||||
Release
|
||||
Schedule
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://wiki.openstack.org/wiki/Release_Cycle">
|
||||
Release
|
||||
Cycle
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<ul class="breadcrumbs">
|
||||
<li>
|
||||
To appear in this page, blueprints must have their
|
||||
<i>Series goal</i> set to {{ series }}
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="breadcrumbs">
|
||||
<li>
|
||||
Page refreshed at {{ date }} UTC
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="span-4 last">
|
||||
<div id="chart_div">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h2>
|
||||
Completed features
|
||||
</h2>
|
||||
<ul class="breadcrumbs">
|
||||
<li>
|
||||
{{ pastbps|length }} completed blueprints
|
||||
</li>
|
||||
</ul>
|
||||
<table class="listing sortable" id="speclisting">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortprio" onclick="ts_resortTable(this); return false;">
|
||||
Priority
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortproject" onclick="ts_resortTable(this); return false;">
|
||||
Project
|
||||
<img class="sortarrow" height="6" src="arrowDown" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortmilestone" onclick="ts_resortTable(this); return false;">
|
||||
Milestone
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" onclick="ts_resortTable(this); return false;">
|
||||
Blueprint
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" onclick="ts_resortTable(this); return false;">
|
||||
Assignee
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% macro render_bp(bp) -%}
|
||||
<tr>
|
||||
<td>
|
||||
<span class="sortkey">
|
||||
{{ bp.priorityindex }}
|
||||
</span>
|
||||
<span class="specpriority{{ bp.priority|upper }}">
|
||||
{{ bp.priority }}
|
||||
</span>
|
||||
{% if bp.priority == 'Undefined' %}
|
||||
<img src="alert.png" title="Priority for blueprint should be defined"/>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://blueprints.launchpad.net/{{bp.pname}}/{{series}}">
|
||||
{{bp.pname}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="sortkey">
|
||||
{{bp.milestonedate}}
|
||||
</span>
|
||||
<a href="{{bp.milestonelink}}">
|
||||
{{bp.milestonename}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://blueprints.launchpad.net/{{bp.pname}}/+spec/{{bp.name}}">
|
||||
{{bp.name}}
|
||||
</a>
|
||||
</td>
|
||||
{% if bp.implementation != 'Implemented' %}
|
||||
<td>
|
||||
<span class="sortkey">
|
||||
{{bp.implementationindex}}
|
||||
</span>
|
||||
<span class="specdelivery{{bp.implementation|replace(' ','')|upper}}">
|
||||
{{bp.implementation}}
|
||||
</span>
|
||||
{% for review in bp.reviews %}
|
||||
<a href="{{review.url}}" title="{{review.subject}}">
|
||||
<img src="bmp{{review.image}}.png"/>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% if bp.impl_error %}
|
||||
<img src="error.png" title="{{bp.impl_error}}-"/>
|
||||
{% endif %}
|
||||
{% if bp.impl_warn %}
|
||||
<img src="alert.png" title="{{bp.impl_warn}}-"/>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
<span>
|
||||
<a href="https://launchpad.net/~{{bp.assigneename}}">
|
||||
{{bp.assigneedisplay}}
|
||||
</a>
|
||||
{% if bp.assignee_error %}
|
||||
<img src="error.png" title="{{bp.assignee_error}}-"/>
|
||||
{% endif %}
|
||||
{% if bp.assignee_warn %}
|
||||
<img src="alert.png" title="{{bp.assignee_warn}}-"/>
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{%- endmacro %}
|
||||
{% for bp in pastbps %}{{ render_bp(bp) }}{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
// Sort by default by project, then milestone, then priority
|
||||
ts_resortTable(document.getElementById("sortprio"))
|
||||
ts_resortTable(document.getElementById("sortmilestone"))
|
||||
ts_resortTable(document.getElementById("sortproject"))
|
||||
</script>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<h2>
|
||||
Tracked series work
|
||||
</h2>
|
||||
<ul class="breadcrumbs">
|
||||
<li>{{ activebps|length }} tracked active blueprints</li>
|
||||
</ul>
|
||||
<ul class="breadcrumbs">
|
||||
<li>
|
||||
Key
|
||||
</li>
|
||||
<li>
|
||||
<img src="bmpNEEDSREVIEW.png"/>
|
||||
Proposed change (needs review)
|
||||
</li>
|
||||
<li>
|
||||
<img src="bmpMERGED.png"/>
|
||||
Merged change
|
||||
</li>
|
||||
</ul>
|
||||
<table class="listing sortable" id="speclisting">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortBprio" onclick="ts_resortTable(this); return false;">
|
||||
Priority
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortBproject" onclick="ts_resortTable(this); return false;">
|
||||
Project
|
||||
<img class="sortarrow" height="6" src="arrowDown" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortBmilestone" onclick="ts_resortTable(this); return false;">
|
||||
Milestone
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" onclick="ts_resortTable(this); return false;">
|
||||
Blueprint
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" id="sortBdelivery" onclick="ts_resortTable(this); return false;">
|
||||
Delivery
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="sortheader" href="#" onclick="ts_resortTable(this); return false;">
|
||||
Assignee
|
||||
<img class="sortarrow" height="6" src="arrowBlank" width="9"/>
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for bp in activebps %}{{ render_bp(bp) }}{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
// Sort by default by project, then milestone, then deliveryn then priority
|
||||
ts_resortTable(document.getElementById("sortBprio"))
|
||||
ts_resortTable(document.getElementById("sortBdelivery"))
|
||||
ts_resortTable(document.getElementById("sortBmilestone"))
|
||||
ts_resortTable(document.getElementById("sortBproject"))
|
||||
</script>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
footer();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|