Refactor all parameters to configuration.yaml

This change moves parameter from utils.py and index.rst to the
configuration.yaml. Moreover this change does:

* Use ISO 8601 dateformat in configuration
* Change events extension to use datetime instead of calendar
* Add a configuration extension to render doc substitutions

Change-Id: Ie35cb9ae2c334814afaa36b3afd606c8bcf62616
This commit is contained in:
Tristan Cacqueray 2016-11-07 03:23:46 +00:00
parent f6507b695d
commit df232c3074
15 changed files with 91 additions and 42 deletions

View File

@ -1,4 +1,16 @@
--- ---
release: ocata
tag: 'sept-2016-elections'
timeframe:
name: 'Mitaka-Newton'
start: '2015-09-05T00:00'
end: '2016-09-04T23:59'
email_deadline: '2016-09-18T23:59'
tc_seats: 6
timeline: timeline:
- name: 'PTL nomination' - name: 'PTL nomination'
start: '2016-09-12T00:00' start: '2016-09-12T00:00'
@ -12,3 +24,6 @@ timeline:
- name: 'TC elections' - name: 'TC elections'
start: '2016-10-03T00:00' start: '2016-10-03T00:00'
end: '2016-10-09T23:45' end: '2016-10-09T23:45'
past_elections:
- ocata

View File

@ -83,7 +83,7 @@ def build_lists(app):
" :titlesonly:", " :titlesonly:",
"" ""
] ]
for previous in utils.PAST_ELECTIONS: for previous in utils.conf['past_elections']:
if build_archive(previous, "ptl"): if build_archive(previous, "ptl"):
previous_toc.append(" %s/ptl.rst" % previous) previous_toc.append(" %s/ptl.rst" % previous)
if build_archive(previous, "tc"): if build_archive(previous, "tc"):

View File

@ -0,0 +1,4 @@
.. |Timeframe| replace:: {{ timeframe['name'] }} timeframe ({{ timeframe['start_str'] }} to {{ timeframe['end_str'] }})
.. |PreferredEmailDeadLine| replace:: {{ timeframe['email_deadline_str'] }}
.. |Projects.yaml| replace:: https://git.openstack.org/cgit/openstack/governance/tree/reference/projects.yaml?id={{ tag }}
.. |TCSeats| replace:: {{ tc_seats }}

View File

@ -0,0 +1,35 @@
# 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.
"""Build configuration substitution
"""
import jinja2
import jinja2.environment
import os
from openstack_election.utils import conf
def build_configuration(app):
output_file = os.path.join(".", "doc", "source", "configuration.rst")
template_dir = os.path.join(".", "doc", "source", "_exts")
loader = jinja2.FileSystemLoader(template_dir)
env = jinja2.environment.Environment(trim_blocks=True, loader=loader)
template = env.get_template("configuration.jinja")
with open(output_file, "w") as out:
out.write(template.render(conf))
def setup(app):
app.info('loading configuration extension')
app.connect('builder-inited', build_configuration)

View File

@ -5,7 +5,7 @@
<script> <script>
var events_timeline = [ var events_timeline = [
{% for event in events %} {% for event in events %}
{ start: "{{ event['start'] }}", end: "{{ event['end'] }}", name: "{{ event['name'] }}" }, { start: "{{ event['start_iso'] }}", end: "{{ event['end_iso'] }}", name: "{{ event['name'] }}" },
{% endfor %} {% endfor %}
]; ];
</script> </script>

View File

@ -13,30 +13,23 @@
"""Add election timer data """Add election timer data
""" """
import calendar import datetime
import jinja2 import jinja2
import jinja2.environment import jinja2.environment
import os import os
import time import pytz
from openstack_election import utils from openstack_election import utils
def build_timer(app): def build_timer(app):
app.add_javascript("event_timer.js") app.add_javascript("event_timer.js")
now = time.time() now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
first_event = True first_event = True
for ev in utils.conf['timeline']: for ev in utils.conf['timeline']:
ds, hs = ev['start'].split('T') if ev['start'] > now:
de, he = ev['end'].split('T')
start_time = calendar.timegm(
time.strptime(ev['start'], "%Y-%m-%dT%H:%M"))
end_time = calendar.timegm(
time.strptime(ev['end'], "%Y-%m-%dT%H:%M"))
if start_time > now:
ev['status'] = 'future' ev['status'] = 'future'
elif end_time > now: elif ev['end'] > now:
ev['status'] = 'current' ev['status'] = 'current'
else: else:
ev['status'] = 'past' ev['status'] = 'past'
@ -51,8 +44,8 @@ def build_timer(app):
elif ev['status'] == 'past': elif ev['status'] == 'past':
mark = '*' mark = '*'
ev['start_str'] = "%s%s, %s UTC%s" % (mark, ds, hs, mark) ev['start_iso'] = ev['start'].strftime("%Y-%m-%dT%H:%M")
ev['end_str'] = "%s%s, %s UTC%s" % (mark, de, he, mark) ev['end_iso'] = ev['end'].strftime("%Y-%m-%dT%H:%M")
ev['name_str'] = "%s%s%s" % (mark, ev['name'], mark) ev['name_str'] = "%s%s%s" % (mark, ev['name'], mark)
output_file = os.path.join(".", "doc", "source", "events.rst") output_file = os.path.join(".", "doc", "source", "events.rst")
with open(output_file, "w") as out: with open(output_file, "w") as out:

View File

@ -32,6 +32,7 @@ extensions = [
'oslosphinx', 'oslosphinx',
'candidates', 'candidates',
'events', 'events',
'configuration',
] ]
todo_include_todos = True todo_include_todos = True

View File

@ -1,8 +1,4 @@
.. TODO: Update below definition for new elections .. include:: configuration.rst
.. |Timeframe| replace:: Mitaka-Newton timeframe (September 5, 2015 00:00 UTC to September 4, 2016 23:59 UTC)
.. |PreferredEmailDeadLine| replace:: September 18, 2016
.. |Projects.yaml| replace:: http://git.openstack.org/cgit/openstack/governance/tree/reference/projects.yaml?id=sept-2016-elections
.. |TCSeats| replace:: 6
================== ==================
OpenStack Election OpenStack Election

View File

@ -31,6 +31,7 @@ def check_candidate(project_name, email, projects, limit=1):
found = 0 found = 0
branch = None branch = None
timeframe = utils.conf['timeframe']
if project_name in ['Stable branch maintenance']: if project_name in ['Stable branch maintenance']:
project_list = projects.values() project_list = projects.values()
@ -50,8 +51,8 @@ def check_candidate(project_name, email, projects, limit=1):
for repo_name in deliverable["repos"]: for repo_name in deliverable["repos"]:
query = ('is:merged after:"%s" before:"%s" ' query = ('is:merged after:"%s" before:"%s" '
'owner:%s project:%s' % 'owner:%s project:%s' %
(utils.gerrit_datetime(utils.PERIOD_START), (utils.gerrit_datetime(timeframe['start']),
utils.gerrit_datetime(utils.PERIOD_END), utils.gerrit_datetime(timeframe['end']),
email, repo_name)) email, repo_name))
if branch: if branch:
query += (' branch:%s' % (branch)) query += (' branch:%s' % (branch))
@ -70,7 +71,7 @@ def check_candidate(project_name, email, projects, limit=1):
return found return found
def check_candidacy_review(change_id, limit=1, tag=utils.PROJECTS_TAG, def check_candidacy_review(change_id, limit=1, tag=utils.conf['tag'],
review=None): review=None):
projects = utils.get_projects(tag=tag) projects = utils.get_projects(tag=tag)
# If there is more than one review that matches this change_id then all # If there is more than one review that matches this change_id then all

View File

@ -23,7 +23,7 @@ from openstack_election import utils
def get_reviews(): def get_reviews():
return utils.get_reviews('is:open project:%s file:^%s/%s/.*' % return utils.get_reviews('is:open project:%s file:^%s/%s/.*' %
(utils.ELECTION_REPO, utils.CANDIDATE_PATH, (utils.ELECTION_REPO, utils.CANDIDATE_PATH,
utils.SERIES_NAME)) utils.conf['release']))
def main(): def main():
@ -34,7 +34,7 @@ def main():
help=('How many validating changes to report. ' help=('How many validating changes to report. '
'A negative value means report many. ' 'A negative value means report many. '
'Default: %(default)s')) 'Default: %(default)s'))
parser.add_argument('--tag', dest='tag', default=utils.PROJECTS_TAG, parser.add_argument('--tag', dest='tag', default=utils.conf['tag'],
help=('The governance tag to validate against. ' help=('The governance tag to validate against. '
'Default: %(default)s')) 'Default: %(default)s'))

View File

@ -29,7 +29,7 @@ def main():
help=('How many validating changes to report. ' help=('How many validating changes to report. '
'A negative value means report many. ' 'A negative value means report many. '
'Default: %(default)s')) 'Default: %(default)s'))
parser.add_argument('--tag', dest='tag', default=utils.PROJECTS_TAG, parser.add_argument('--tag', dest='tag', default=utils.conf['tag'],
help=('The governance tag to validate against. ' help=('The governance tag to validate against. '
'Default: %(default)s')) 'Default: %(default)s'))

View File

@ -32,7 +32,7 @@ def main():
help=('How many validating changes to report. ' help=('How many validating changes to report. '
'A negative value means report many. ' 'A negative value means report many. '
'Default: %(default)s')) 'Default: %(default)s'))
parser.add_argument('--tag', dest='tag', default=utils.PROJECTS_TAG, parser.add_argument('--tag', dest='tag', default=utils.conf['tag'],
help=('The governance tag to validate against. ' help=('The governance tag to validate against. '
'Default: %(default)s')) 'Default: %(default)s'))

View File

@ -74,7 +74,7 @@ def main():
parser = argparse.ArgumentParser(description=desc) parser = argparse.ArgumentParser(description=desc)
parser.add_argument('-v', '--verbose', action="count", default=0, parser.add_argument('-v', '--verbose', action="count", default=0,
help='Increase program verbosity') help='Increase program verbosity')
parser.add_argument('-r', '--release', default=utils.SERIES_NAME, parser.add_argument('-r', '--release', default=utils.conf['release'],
help='Which nominations to look at') help='Which nominations to look at')
parser.add_argument('-b', '--basedir', parser.add_argument('-b', '--basedir',
default=os.getcwd(), default=os.getcwd(),

View File

@ -66,7 +66,7 @@ def main():
parser = argparse.ArgumentParser(description='Investigate Nominations') parser = argparse.ArgumentParser(description='Investigate Nominations')
parser.add_argument('-v', '--verbose', action="count", default=0, parser.add_argument('-v', '--verbose', action="count", default=0,
help='Increase program verbosity') help='Increase program verbosity')
parser.add_argument('-r', '--release', default=utils.SERIES_NAME, parser.add_argument('-r', '--release', default=utils.conf['release'],
help='Which nominations to look at') help='Which nominations to look at')
parser.add_argument('-b', '--basedir', parser.add_argument('-b', '--basedir',
default=os.getcwd(), default=os.getcwd(),

View File

@ -26,14 +26,6 @@ import time
import urllib import urllib
import yaml import yaml
# Per election constants
SERIES_NAME = 'ocata'
# 2015-09-05 00:00:00 +0000
PERIOD_START = datetime.datetime(2015, 9, 5, 0, 0, 0, tzinfo=pytz.utc)
# 2016-09-04 23:59:59 +0000
PERIOD_END = datetime.datetime(2016, 9, 4, 23, 59, 59, tzinfo=pytz.utc)
PROJECTS_TAG = 'sept-2016-elections'
# Library constants # Library constants
CANDIDATE_PATH = 'candidates' CANDIDATE_PATH = 'candidates'
@ -42,10 +34,22 @@ ELECTION_REPO = 'openstack/election'
CGIT_URL = 'https://git.openstack.org/cgit' CGIT_URL = 'https://git.openstack.org/cgit'
PROJECTS_URL = ('%s/openstack/governance/plain/reference/projects.yaml' % PROJECTS_URL = ('%s/openstack/governance/plain/reference/projects.yaml' %
(CGIT_URL)) (CGIT_URL))
TIME_FMT = "%b %d, %Y %H:%M %Z"
PAST_ELECTIONS = ['ocata'] # Election configuration
conf = yaml.load(open('configuration.yaml')) conf = yaml.load(open('configuration.yaml'))
# Convert time to datetime object
strptime = lambda x: datetime.datetime.strptime(
x, "%Y-%m-%dT%H:%M").replace(tzinfo=pytz.utc)
for key in ('start', 'end', 'email_deadline'):
conf['timeframe'][key] = strptime(conf['timeframe'][key])
conf['timeframe'][key+'_str'] = conf['timeframe'][key].strftime(TIME_FMT)
for event in conf['timeline']:
for key in ('start', 'end'):
event[key] = strptime(event[key])
event[key+'_str'] = event[key].strftime(TIME_FMT)
exceptions = None exceptions = None
@ -133,7 +137,7 @@ def check_atc_date(atc):
return False return False
expires_in = datetime.datetime.strptime(atc['expires-in'], '%B %Y') expires_in = datetime.datetime.strptime(atc['expires-in'], '%B %Y')
expires_in = expires_in.replace(tzinfo=pytz.utc) expires_in = expires_in.replace(tzinfo=pytz.utc)
return PERIOD_END < expires_in return conf['timeframe']['end'] < expires_in
def get_projects(tag=None): def get_projects(tag=None):
@ -172,7 +176,7 @@ def dir2name(name, projects):
raise ValueError(('%s does not match any project' % (name))) raise ValueError(('%s does not match any project' % (name)))
def build_candidates_list(election=SERIES_NAME): def build_candidates_list(election=conf['release']):
project_list = os.listdir(os.path.join(CANDIDATE_PATH, election)) project_list = os.listdir(os.path.join(CANDIDATE_PATH, election))
project_list.sort() project_list.sort()
candidates_lists = {} candidates_lists = {}