056184c363
Change-Id: I216b77823281abe390e35395ac8d9ccc7f3064b9
177 lines
6.6 KiB
Python
177 lines
6.6 KiB
Python
# 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 argparse
|
|
import datetime
|
|
import os
|
|
import sys
|
|
import textwrap
|
|
|
|
from openstack_election import config
|
|
from openstack_election import yamlutils
|
|
|
|
conf = config.load_conf()
|
|
rst_template = textwrap.dedent("""
|
|
{release} TC and PTL Elections
|
|
---------------------------
|
|
|
|
.. _{nrl}-election-email-deadline:
|
|
|
|
{release} Election Email Deadline
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
Contributors that will be in the electorate for the upcoming election
|
|
should confirm their gerrit email addresses by this date ({deadline_date}
|
|
at {deadline_time} UTC). Electorate rolls are generated after this date and ballots will
|
|
be sent to the listed gerrit email address.
|
|
|
|
.. _{nrl}-election-nominations:
|
|
|
|
{release} Election Nomination Begins
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
Candidates interested in serving for the next calendar year (TC), or
|
|
development cycle (PTL) should announce their candidacies and platforms during
|
|
this week. Please see the `Election site`_ for specific timing information.
|
|
|
|
.. _{nrl}-election-campaigning:
|
|
|
|
{release} Election Campaigning Begins
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
The electorate has time to ask candidates questions about their platforms
|
|
and debate topics before polling begins. Please see the `Election site`_ for
|
|
specific timing information.
|
|
|
|
.. _{nrl}-election-voting:
|
|
|
|
{release} Election Polling Begins
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
Election polling for open seats on the TC and any required PTL elections.
|
|
Please see the `Election site`_ for specific timing information.
|
|
|
|
.. _{nrl}-election-close:
|
|
|
|
{release} Election Polling Ends
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
All polls close in the {release} Election and results announced. Please see the
|
|
`Election site`_ for specific timing information.
|
|
|
|
.. _Election site: https://governance.openstack.org/election/
|
|
""") # noqa
|
|
|
|
|
|
def next_release_letter(release_name):
|
|
ord_a = ord('a')
|
|
next_ord = (ord(release_name[0]) - ord_a + 1) % 26
|
|
next_letter = chr(ord_a + next_ord)
|
|
return next_letter
|
|
|
|
|
|
def custom_strftime(format, t):
|
|
def _suffix(d):
|
|
return {1: 'st', 2: 'nd', 3: 'rd'}.get(d % 20, 'th')
|
|
return t.strftime(format).replace('{S}', str(t.day) + _suffix(t.day))
|
|
|
|
|
|
def add_election_event_to_schedule(nrl, election_events,
|
|
schedule_events, schedule_data):
|
|
election_event_idx = 0
|
|
for cycle_event in schedule_data["cycle"]:
|
|
(cycle_event_start, cycle_event_end) = (
|
|
datetime.date.fromisoformat(cycle_event["start"]),
|
|
datetime.date.fromisoformat(cycle_event["end"]))
|
|
event_type = election_events[election_event_idx]
|
|
event_label = f"{nrl}-election-{event_type}"
|
|
(event_start, event_end) = schedule_events[event_label]
|
|
|
|
if cycle_event_start < event_start.date():
|
|
continue
|
|
|
|
if "x-project" not in cycle_event:
|
|
cycle_event["x-project"] = []
|
|
if event_label not in cycle_event["x-project"]:
|
|
cycle_event["x-project"].append(event_label)
|
|
|
|
if event_end.date() < cycle_event_end:
|
|
election_event_idx += 1
|
|
if election_event_idx >= len(election_events):
|
|
break
|
|
|
|
|
|
def main():
|
|
if conf["election_type"] != "combined":
|
|
print("This tool currently only supports 'combined' elections",
|
|
file=sys.stderr)
|
|
return 1
|
|
|
|
description = ('Update development cycle in openstack/releases with '
|
|
' key election events')
|
|
parser = argparse.ArgumentParser(description)
|
|
parser.add_argument('--releases-repo', dest='releases_repo',
|
|
required=True,
|
|
help=('Path to a clone of the releases repo'))
|
|
|
|
args = parser.parse_args()
|
|
|
|
series_path = os.path.join(args.releases_repo, "data",
|
|
"series_status.yaml")
|
|
with open(series_path) as f:
|
|
series_data = yamlutils.loads(f)
|
|
|
|
release = conf.get("release")
|
|
release_name = series_data[0]["name"]
|
|
nrl = next_release_letter(release_name)
|
|
|
|
schedule_path = os.path.join(args.releases_repo, "doc", "source",
|
|
release_name, "schedule.yaml")
|
|
with open(schedule_path) as f:
|
|
schedule_data = yamlutils.loads(f)
|
|
|
|
rst_path = os.path.join(args.releases_repo, "doc", "source", release_name,
|
|
"schedule.rst")
|
|
with open(rst_path) as f:
|
|
rst = f.read()
|
|
|
|
email_deadline = conf["timeframe"]["email_deadline"]
|
|
deadline_date = custom_strftime('%B {S}, %Y', email_deadline)
|
|
deadline_time = email_deadline.strftime("%H:%M")
|
|
rst_blob = rst_template.format(**dict(release=release,
|
|
nrl=nrl,
|
|
deadline_time=deadline_time,
|
|
deadline_date=deadline_date,))
|
|
election_canary = rst_blob.split("\n")[1]
|
|
if election_canary not in rst:
|
|
print(f"Updating {rst_path} to add {rst_blob}\n")
|
|
with open(rst_path, "w") as f:
|
|
f.write(rst)
|
|
f.write(rst_blob)
|
|
|
|
schedule_events = {f"{nrl}-election-close":
|
|
(conf["timeframe"]["end"], conf["timeframe"]["end"]),
|
|
f"{nrl}-election-email-deadline":
|
|
(email_deadline, email_deadline), }
|
|
for event in conf["timeline"]:
|
|
event_type = event["name"].split()[-1].lower()
|
|
if event_type == "election":
|
|
event_type = "voting"
|
|
event_label = f"{nrl}-election-{event_type}"
|
|
schedule_events[event_label] = (event["start"], event["end"])
|
|
|
|
election_events = ["email-deadline"]
|
|
add_election_event_to_schedule(nrl, election_events, schedule_events,
|
|
schedule_data)
|
|
election_events = ["nominations", "campaigning", "voting", "close"]
|
|
add_election_event_to_schedule(nrl, election_events, schedule_events,
|
|
schedule_data)
|
|
|
|
with open(schedule_path, "w") as f:
|
|
print(f"Updating {schedule_path}")
|
|
f.write(yamlutils.dumps(schedule_data))
|