diff --git a/gerrit-powered-agenda/const.py b/gerrit-powered-agenda/const.py index 4642253..3d157f7 100644 --- a/gerrit-powered-agenda/const.py +++ b/gerrit-powered-agenda/const.py @@ -31,4 +31,4 @@ DEFAULT_YAML_DIR = '../meetings' DEFAULT_ICAL_DIR = '../icals' # NOTE(jotan): The following publish URL is for testing purposes only. # It should be later changed to the official OpenStack Meetings Wiki. -DEFAULT_PUBLISH_URL = 'https://wiki.openstack.org/wiki/Meetings_Autogenerated' +PUBLISH_URL = 'https://wiki.openstack.org/wiki/Meetings_Autogenerated' diff --git a/gerrit-powered-agenda/jobs.py b/gerrit-powered-agenda/jobs.py index e25b0a7..9febeca 100644 --- a/gerrit-powered-agenda/jobs.py +++ b/gerrit-powered-agenda/jobs.py @@ -16,11 +16,10 @@ # under the License. import logging +from argparse import ArgumentParser, RawDescriptionHelpFormatter import os -import yaml import const -from meeting import Meeting import util @@ -29,22 +28,13 @@ logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', level=logging.DEBUG) -def execute_check(): +def execute_check(yaml_dir, ical_dir): """Execute check job.""" logging.info('Check job initiated.') - # NOTE(jotan): once a CLI parameter for YAML_DIR has been - # implemented, only use DEFAULT_YAML_DIR if the parameter has - # not been supplied - yaml_dir = const.DEFAULT_YAML_DIR - - meetings = __load_meetings(yaml_dir) - # convert meetings to a list of ical - for m in meetings: - m.write_ical() - logging.info('Wrote %d meetings to iCal' % (len(meetings))) + util.convert_yaml_to_ical(yaml_dir, ical_dir) os.chdir(const.SRC_DIR) if util.check_uniqueness() == 0: @@ -55,7 +45,7 @@ def execute_check(): return 1 -def execute_gate(): +def execute_gate(yaml_dir): """Execute gate job.""" logging.info('Gate job initiated.') @@ -65,33 +55,109 @@ def execute_gate(): return result -def execute_post(): +def execute_post(yaml_dir, ical_dir, publish_url): """Execute post job.""" logging.info('Post job initiated.') - yaml_dir = const.DEFAULT_YAML_DIR - meetings = __load_meetings(yaml_dir) # convert meetings to a list of ical - for m in meetings: - m.write_ical() - logging.info('Wrote %d meetings to iCal' % (len(meetings))) + util.convert_yaml_to_ical(yaml_dir, ical_dir) + logging.info('Post job finished.') - -def __load_meetings(yaml_dir): - """Return a list of Meetings initialized from files in yaml_dir.""" - - os.chdir(yaml_dir) - meetings_yaml = [f for f in os.listdir() - if os.path.isfile(f) and - f.endswith(const.YAML_FILE_EXT)] - meetings = [Meeting(yaml.load(open(f, 'r')), f) - for f in meetings_yaml] - logging.info('Loaded %d meetings from YAML' % (len(meetings))) - os.chdir(const.SRC_DIR) - return meetings - - # entry point -execute_check() +if __name__ == '__main__': + + # build option parser: + description = """ +A tool that automates the process for testing, integrating, and +publishing changes to OpenStack meetings using the existing OpenStack +project infrastructure. +""" + + epilog = """ +This program is meant to be invoked as a Jenkins job during check, +gate, and post tests. Depending on which test invokes the program, +it will perform different activites. + +Check: + - Verify correct YAML syntax for proposed meeting changes. + - Verify YAML files can be converted to valid iCal files + - Test that proposed changes would not result in scheduling + conflicts + +Gate: + - Test that proposed changes would not result in scheduling + conflicts (including conflicts with changes that have been + made since the inital check test). + +Post: + - Convert YAML files to iCal files + - Publish meeting changes and associated iCal files to a + public wiki location +""" + parser = ArgumentParser( + formatter_class=RawDescriptionHelpFormatter, + description=description, + epilog=epilog) + + parser.add_argument("-t", "--test", + help="test to execute. valid values are check,\ + gate, and post.") + parser.add_argument("-c", "--convert", + action="store_true", + default=False, + help="convert meeting YAML to iCal format.") + parser.add_argument("-y", "--yamldir", + dest="yaml_dir", + default=const.DEFAULT_YAML_DIR, + help="directory containing YAML to process") + parser.add_argument("-m", "--meetings", + dest="meeting_list_file", + help="name of file containing meetings to \ + process. meetings are specified by filename,\ + which correspond to meeting filenames in\ + yamldir. filenames should be separated by\ + newlines.") + parser.add_argument("-i", "--icaldir", + dest="ical_dir", + default=const.DEFAULT_ICAL_DIR, + help="directory to store converted iCal") + + # parse arguments: + args = parser.parse_args() + + test = args.test + convert = args.convert + yaml_dir = args.yaml_dir + meeting_list_file = args.meeting_list_file + ical_dir = args.ical_dir + + if (yaml_dir and not os.path.isdir(yaml_dir)): + parser.error("invalid YAML directory provided") + if (ical_dir and not os.path.isdir(ical_dir)): + parser.error("invalid iCal directory provided") + + if not test and not convert: + parser.error( + "invalid arguments. must specify test or convert") + elif test: + if test == "check": + execute_check(yaml_dir, ical_dir) + elif test == "gate": + execute_gate(yaml_dir) + elif test == "post": + execute_post(yaml_dir, ical_dir, const.PUBLISH_URL) + else: + parser.error("invalid test provided") + elif convert: + # if file containing list of meetings provided + if meeting_list_file: + if not os.path.isfile(meeting_list_file): + parser.error("meeting list file does not exist") + util.convert_yaml_to_ical(yaml_dir, + ical_dir, + meeting_list_file) + else: + # convert all meetings in yaml_dir + util.convert_yaml_to_ical(yaml_dir, ical_dir) diff --git a/gerrit-powered-agenda/meeting.py b/gerrit-powered-agenda/meeting.py index 6867696..cdfa89f 100644 --- a/gerrit-powered-agenda/meeting.py +++ b/gerrit-powered-agenda/meeting.py @@ -43,7 +43,7 @@ class Meeting: # create schedule objects self.schedules = [Schedule(schedule) for schedule in yaml['schedule']] - def write_ical(self): + def write_ical(self, ical_dir): """Write this meeting to disk using the iCal format.""" cal = icalendar.Calendar() @@ -99,7 +99,6 @@ class Meeting: cal.add_component(event) # write ical files to disk - ical_dir = const.DEFAULT_ICAL_DIR ical_filename = self.filename[:-4] + 'ics' if not os.path.exists(ical_dir): diff --git a/gerrit-powered-agenda/util.py b/gerrit-powered-agenda/util.py index 6e101bf..ab26e8a 100644 --- a/gerrit-powered-agenda/util.py +++ b/gerrit-powered-agenda/util.py @@ -34,6 +34,52 @@ def publish(meeting, ical): pass +def load_meetings(yaml_dir, meeting_list=None): + """Return a list of Meetings initialized from files in yaml_dir.""" + + os.chdir(yaml_dir) + if meeting_list: + meetings_yaml = [f for f in os.listdir() + if os.path.isfile(f) and + f.endswith(const.YAML_FILE_EXT) and + f in meeting_list] + else: + meetings_yaml = [f for f in os.listdir() + if os.path.isfile(f) and + f.endswith(const.YAML_FILE_EXT)] + + meetings = [Meeting(yaml.load(open(f, 'r')), f) + for f in meetings_yaml] + + logging.info('Loaded %d meetings from YAML' % (len(meetings))) + + return meetings + + +def convert_yaml_to_ical(yaml_dir, ical_dir, meeting_list_file=None): + """Convert meeting YAML files to the iCal format and place + in ical_dir. If meeting_list is specified, only those meetings + in yaml_dir with filenames contained in meeting_list are + converted; otherwise, all meeting in yaml_dir are converted. + + """ + + meeting_list = None + if meeting_list_file: + meeting_list = open(meeting_list_file).read().splitlines() + + meetings = load_meetings(yaml_dir, + meeting_list) + + # convert meetings to a list of ical + for m in meetings: + m.write_ical(ical_dir) + + # TODO(jotan): verify converted ical is valid + + logging.info('Wrote %d meetings to iCal' % (len(meetings))) + + def check_uniqueness(): """Check for uniqueness in meeting room and time combination. During gate job, we do not care about the meeting name. diff --git a/meetings/ironic-team-meeting.yml b/meetings/ironic-team-meeting.yml index a765f53..1d43883 100644 --- a/meetings/ironic-team-meeting.yml +++ b/meetings/ironic-team-meeting.yml @@ -1,7 +1,7 @@ project: Ironic team Meeting schedule: - time: '1900' - day: Mondays + day: Monday irc: openstack-meeting frequency: weekly chair: Devananda van der Veen diff --git a/meetings/nova-team-meeting.yml b/meetings/nova-team-meeting.yml deleted file mode 100644 index 6689e4d..0000000 --- a/meetings/nova-team-meeting.yml +++ /dev/null @@ -1,20 +0,0 @@ -project: Nova Team meeting -schedule: - - time: '1400' - day: Thursday - irc: openstack-meeting-alt - frequency: biweekly - - time: '2100' - day: Thursday - irc: openstack-meeting - frequency: biweekly -chair: Russell Bryant -description: > - This meeting is a weekly gathering of developers working on OpenStack Compute - (NOVA). We cover topics such as release and planning and status, bugs, - reviews, and other current topics worthy of real-time discussion -agenda: | - *Icehouse-rc - *other bugs - *blueprints - *Open Discussion diff --git a/requirements.txt b/requirements.txt index ab63889..044ed0a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ pbr pyyaml icalendar +argparse