def get_project(self, shortname):
     """
     Try and retrieve a project for this user, with the given shortname
     :param shortname:
     :return:
     """
     return Project.get(self._id, shortname)
 def create_project(self, shortname, title):
     """
     Create a new project
     :param shortname:
     :param title:
     :return:
     """
     return Project.create(self._id, shortname, title)
示例#3
0
 def get_projects(self, filter_by=None, filter=None):
     """
     Get all of the user's projects
     @param filter_by:
     @param filter:
     @return:
     """
     return Project.all(self._id, filter_by, filter)
    async def complete(self, context=None, bot=None):
        """
        Finish the sprint, calculate all the WPM and XP and display results
        :return:
        """

        # Print the 'Results coming up shortly' message
        await self.say(lib.get_string('sprint:resultscomingsoon', self._guild),
                       context, bot)

        # Create array to use for storing the results
        results = []

        # If the sprint has already completed, stop.
        if self._completed != 0:
            return

        # Mark this sprint as complete so the cron doesn't pick it up and start processing it again
        self.set_complete()

        # Get all the users taking part
        users = self.get_users()

        # Loop through them and get their full sprint info
        for user_id in users:

            user = User(user_id,
                        self._guild,
                        context=context,
                        bot=bot,
                        channel=self.get_channel())
            user_sprint = self.get_user_sprint(user_id)

            # If it's a non-word count sprint, we don't need to do anything with word counts.
            if user_sprint['sprint_type'] == Sprint.SPRINT_TYPE_NO_WORDCOUNT:

                # Just give them the completed sprint stat and XP.
                await user.add_xp(Experience.XP_COMPLETE_SPRINT)
                user.add_stat('sprints_completed', 1)

                # Push user to results
                results.append({
                    'user': user,
                    'wordcount': 0,
                    'xp': Experience.XP_COMPLETE_SPRINT,
                    'type': user_sprint['sprint_type']
                })

            else:

                # If they didn't submit an ending word count, use their current one
                if user_sprint['ending_wc'] == 0:
                    user_sprint['ending_wc'] = user_sprint['current_wc']

                # Now we only process their result if they have declared something and it's different to their starting word count
                user_sprint['starting_wc'] = int(user_sprint['starting_wc'])
                user_sprint['current_wc'] = int(user_sprint['current_wc'])
                user_sprint['ending_wc'] = int(user_sprint['ending_wc'])
                user_sprint['timejoined'] = int(user_sprint['timejoined'])

                if user_sprint['ending_wc'] > 0 and user_sprint[
                        'ending_wc'] != user_sprint['starting_wc']:

                    wordcount = user_sprint['ending_wc'] - user_sprint[
                        'starting_wc']
                    time_sprinted = self._end_reference - user_sprint[
                        'timejoined']

                    # If for some reason the timejoined or sprint.end_reference are 0, then use the defined sprint length instead
                    if user_sprint[
                            'timejoined'] <= 0 or self._end_reference == 0:
                        time_sprinted = self._length

                    # Calculate the WPM from their time sprinted
                    wpm = Sprint.calculate_wpm(wordcount, time_sprinted)

                    # See if it's a new record for the user
                    user_record = user.get_record('wpm')
                    wpm_record = True if user_record is None or wpm > int(
                        user_record) else False

                    # If it is a record, update their record in the database
                    if wpm_record:
                        user.update_record('wpm', wpm)

                    # Give them XP for finishing the sprint
                    await user.add_xp(Experience.XP_COMPLETE_SPRINT)

                    # Increment their stats
                    user.add_stat('sprints_completed', 1)
                    user.add_stat('sprints_words_written', wordcount)
                    user.add_stat('total_words_written', wordcount)

                    # Increment their words towards their goal
                    await user.add_to_goals(wordcount)

                    # If they were writing in a Project, update its word count.
                    if user_sprint['project'] is not None:
                        project = Project(user_sprint['project'])
                        project.add_words(wordcount)

                    # is there an event running on this server?
                    event = Event.get_by_guild(self._guild)
                    if event and event.is_running():
                        event.add_words(user.get_id(), wordcount)

                    # Push user to results
                    results.append({
                        'user': user,
                        'wordcount': wordcount,
                        'wpm': wpm,
                        'wpm_record': wpm_record,
                        'xp': Experience.XP_COMPLETE_SPRINT,
                        'type': user_sprint['sprint_type']
                    })

        # Sort the results
        results = sorted(results, key=itemgetter('wordcount'), reverse=True)

        # Now loop through them again and apply extra XP, depending on their position in the results
        position = 1
        highest_word_count = 0

        for result in results:

            if result['wordcount'] > highest_word_count:
                highest_word_count = result['wordcount']
            # If the user finished in the top 5 and they weren't the only one sprinting, earn extra XP
            is_sprint_winner = result['wordcount'] == highest_word_count
            if position <= 5 and len(results) > 1:

                extra_xp = math.ceil(
                    Experience.XP_WIN_SPRINT /
                    (self.WINNING_POSITION if is_sprint_winner else position))
                result['xp'] += extra_xp
                await result['user'].add_xp(extra_xp)

            # If they actually won the sprint, increase their stat by 1
            # Since the results are in order, the highest word count will be set first
            # which means that any subsequent users with the same word count have tied for 1st place
            if position == 1 or result['wordcount'] == highest_word_count:
                result['user'].add_stat('sprints_won', 1)

            position += 1

        # Post the final message with the results
        if len(results) > 0:

            position = 1
            message = lib.get_string('sprint:results:header', self._guild)
            for result in results:

                if result['type'] == Sprint.SPRINT_TYPE_NO_WORDCOUNT:
                    message = message + lib.get_string(
                        'sprint:results:row:nowc', self._guild).format(
                            result['user'].get_mention(), result['xp'])
                else:

                    message = message + lib.get_string(
                        'sprint:results:row', self._guild).format(
                            position, result['user'].get_mention(),
                            result['wordcount'], result['wpm'], result['xp'])

                    # If it's a new PB, append that string as well
                    if result['wpm_record'] is True:
                        message = message + lib.get_string(
                            'sprint:results:pb', self._guild)

                message = message + '\n'
                position += 1

        else:
            message = lib.get_string('sprint:nowordcounts', self._guild)

        # Send the message, either via the context or directly to the channel
        await self.say(message, context, bot)
示例#5
0
def main():
    args = parse_args()
    # override log_path if set before actually creating logger
    if args.log_path:
        global_configuration.log_path = args.log_path

    # -------------------------------------------------------

    # now import other packages
    import utils.config as cfgutil
    from utils.logging import logger
    from utils.config import Config as cfg
    from utils.strings import generate_random_key as rands, pad_lines

    from proc.project import ProcessProject
    from structures.project import Project
    import colorama

    colorama.init()

    __root__ = global_configuration.root
    __cfg__ = global_configuration.cfg
    __src__ = global_configuration.src

    # change stream_handler level to info
    logger.set_level('INFO', logger.LOGGER_STREAMHANDLER)
    logger.increase_verbosity(args.verbosity)

    logger.debug('app args: %s', str(args), skip_format=True)

    # convert list ["key:value", "key2:value2", ...] to dict {key:value, key2:value2}
    # default value for this dictionary is string value 'master'
    args.git_branch = dict(tuple(d.split(':', 1)) for d in args.git_branch)
    args.git_branch = defaultdict(lambda: 'master', **args.git_branch)

    # default value for this dictionary is string value ''
    args.git_commit = dict(tuple(d.split(':', 1)) for d in args.git_commit)
    args.git_commit = defaultdict(lambda: '', **args.git_commit)

    # all the paths depend on the project name
    project_name = args.project

    # all configuration files are cfg/<project-name> directory if not set otherwise
    project_dir = args.config_dir if args.config_dir else os.path.join(
        __cfg__, project_name)
    if args.config_dir:
        if not os.path.exists(args.config_dir):
            logger.warning('invalid config location given: %s', project_dir)
            project_dir = os.path.join(__cfg__, project_name)
            logger.warning('will try to use %s instead', project_dir)

    if not os.path.exists(project_dir):
        logger.error('no valid configuration found for the project %s',
                     project_name)
        sys.exit(1)

    # execute on demand using pbs/local or other system
    if args.execute:
        project_execute_path = os.path.join(project_dir, 'execute.sh')
        if os.path.exists(project_execute_path):
            with open(project_execute_path, 'r') as fp:
                project_execute_script = fp.read()
        else:
            project_execute_script = '\n'.join([
                '#!/bin/bash --login',
                'echo "<ci-hpc-install>"',
                '<ci-hpc-install>',
                'echo "<ci-hpc-exec>"',
                '<ci-hpc-exec>',
                'exit $?',
            ])

        install_args = [os.path.join(__root__, 'share', 'install.sh')]
        name = 'tmp.entrypoint-%d-%s.sh' % (time.time(), rands(6))
        bash_path = os.path.join(__root__, 'tmp', name)
        logger.debug('Generating script %s', bash_path)

        with open(bash_path, 'w') as fp:
            exec_args = [
                sys.executable,
                os.path.join(__src__, 'main.py'),
                ' '.join(args.step),
            ]
            for arg in ['project', 'git_url', 'config_dir']:
                value = getattr(args, arg)
                if value:
                    exec_args.append('--%s=%s' %
                                     (arg.replace('_', '-'), str(value)))
            for arg in ['git_branch', 'git_commit']:
                value = getattr(args, arg)
                for k, v in value.items():
                    exec_args.append('--%s=%s:%s' %
                                     (arg.replace('_', '-'), k, v))
            fp.write(
                cfgutil.configure_string(
                    project_execute_script, {
                        'ci-hpc-exec': ' '.join(exec_args),
                        'ci-hpc-install': ' '.join(install_args),
                        'ci-hpc-exec-no-interpret': ' '.join(exec_args[1:]),
                    }))
        os.chmod(bash_path, 0o777)
        logger.debug('ci-hpc-exec set to %s',
                     ' '.join(exec_args),
                     skip_format=True)

        # execute on demand using specific system (local/pbs for now)
        logger.info('executing script %s using %s system', bash_path,
                    args.execute)
        if args.execute == 'local':
            p = subprocess.Popen([bash_path])

            # def cleanup():
            #     logger.info('CLEANING PROCESSES')
            #     os.killpg(0, signal.SIGKILL)
            # atexit.register(cleanup)

            p.wait()

        elif args.execute == 'pbs':
            logger.debug('running cmd: %s',
                         str(['qsub', bash_path]),
                         skip_format=True)

            qsub_output = str(
                subprocess.check_output(['qsub', bash_path]).decode()).strip()
            cmd = [
                sys.executable,
                os.path.join(__src__, 'wait_for.py'),
                qsub_output,
                '--timeout=%d' % args.timeout,
                '--check-interval=%d' % args.check_interval,
                '--live-log=%s' % global_configuration.log_path,
                '--quiet',
            ]
            logger.info('waiting for job (%s) to finish', qsub_output)
            subprocess.Popen(cmd).wait()
        os.unlink(bash_path)
        sys.exit(0)

    if global_configuration.tty:
        logger.info(
            'Started ci-hpc in a %s mode',
            colorama.Back.BLUE + colorama.Fore.CYAN + colorama.Style.BRIGHT +
            ' tty ' + colorama.Style.RESET_ALL)
    else:
        logger.info('Started ci-hpc *not* in a tty mode')

    # this file contains only variables which can be used in config.yaml
    variables_path = os.path.join(project_dir, 'variables.yaml')
    # this file contains all the sections and steps for installation and testing
    config_path = os.path.join(project_dir, 'config.yaml')

    # update cpu count
    variables = cfgutil.load_config(variables_path)
    # variables['cpu-count'] = args.cpu_count

    # load config
    project_config = cfgutil.configure_file(config_path, variables)
    logger.debug('yaml configuration: \n%s',
                 pad_lines(utils.strings.to_yaml(project_config)),
                 skip_format=True)

    # specify some useful global arguments which will be available in the config file
    global_args_extra = {
        'project-name':
        project_name,
        'project-dir':
        project_dir,
        'arg':
        dict(
            branch=defaultdict(lambda: 'master', **dict(args.git_branch)),
            commit=defaultdict(lambda: '', **dict(args.git_commit)),
        )
    }

    # parse config
    project_definition = Project(project_name, **project_config)
    project_definition.update_global_args(global_args_extra)

    project = ProcessProject(project_definition)
    logger.info('processing project %s, section %s', project_name, args.step)

    # -----------------------------------------------------------------

    if 'install' in args.step:
        project.process_section(project_definition.install)

    if 'test' in args.step:
        project.process_section(project_definition.test)
 def get_projects(self):
     """
     Get all of the user's projects
     :return:
     """
     return Project.all(self._id)
示例#7
0
    async def run_join(self, context, arg1=None, arg2=None):
        """
        Join the sprint, with an optional starting word count and project shortname
        :param opt1: Argument 1 of the join command
        :param opt2: Argument 2 of the join command
        :return:
        """
        user = User(context.message.author.id, context.guild.id, context)
        sprint = Sprint(user.get_guild())
        project_id = None
        starting_wc = None
        sprint_type = None

        # If there is no active sprint, then just display an error
        if not sprint.exists():
            return await context.send(
                user.get_mention() + ', ' +
                lib.get_string('sprint:err:noexists', user.get_guild()))

        # Are we using the `same` keyword?
        if arg1 == "same":

            # Okay, check for their most recent sprint record
            most_recent = user.get_most_recent_sprint(sprint)
            if most_recent is not None:
                starting_wc = most_recent['ending_wc']
                project_id = most_recent['project']
                sprint_type = most_recent['sprint_type']

            # Can't use the second argument in this case.
            arg2 = None

        # Are we doing a no wordcount sprint? E.g. we are sprinting or using the functionality for something else.
        elif arg1 in ["edit", "non-wc"]:

            sprint_type = Sprint.SPRINT_TYPE_NO_WORDCOUNT

            # Can't use the second argument in this case.
            arg2 = None

        else:
            # Convert starting_wc to int if we can
            starting_wc = lib.is_number(arg1)

        # If the starting_wc is still False at this point, just set it to 0
        if not starting_wc:
            starting_wc = 0

        # If the user is already sprinting, then just update their starting wordcount
        if sprint.is_user_sprinting(user.get_id()):

            # Update the sprint_users record. We set their current_wc to the same as starting_wc here, otherwise if they join with, say 50 and their current remains 0
            # then if they run a status, or in the ending calculations, it will say they wrote -50.
            sprint.update_user(user.get_id(),
                               start=starting_wc,
                               current=starting_wc,
                               sprint_type=sprint_type)

            # If it's a non-wordcount sprint, send a different message.
            if sprint_type == Sprint.SPRINT_TYPE_NO_WORDCOUNT:
                await context.send(user.get_mention() + ', ' + lib.get_string(
                    'sprint:join:update:no_wordcount', user.get_guild()))
            else:
                # Send message back to channel letting them know their starting word count was updated
                await context.send(user.get_mention() + ', ' + lib.get_string(
                    'sprint:join:update', user.get_guild()).format(starting_wc)
                                   )

        else:

            # Join the sprint
            sprint.join(user.get_id(),
                        starting_wc=starting_wc,
                        sprint_type=sprint_type)

            if sprint_type == Sprint.SPRINT_TYPE_NO_WORDCOUNT:
                await context.send(user.get_mention() + ', ' + lib.get_string(
                    'sprint:join:update:no_wordcount', user.get_guild()))
            else:
                # Send message back to channel letting them know their starting word count was updated
                await context.send(user.get_mention() + ', ' + lib.get_string(
                    'sprint:join', user.get_guild()).format(starting_wc))

        # Currently this is the only usage of argument 2.
        shortname = arg2

        # If a project shortname is supplied, try to set that as what the user is sprinting for.
        if shortname is not None or project_id is not None:

            # Did we supply the project by name?
            if shortname is not None:

                # Convert to lowercase for searching.
                shortname = shortname.lower()

                # Make sure the project exists.
                project = user.get_project(shortname)

            # Or do we already have the ID from using 'same' and getting from previous sprint?
            elif project_id is not None:
                project = Project(project_id)

            # If that did not yield a valid project, send an error message.
            if not project:
                return await context.send(
                    user.get_mention() +
                    ', ' + lib.get_string('project:err:noexists',
                                          user.get_guild()).format(shortname))

            sprint.set_project(project.get_id(), user.get_id())
            return await context.send(
                user.get_mention() + ', ' +
                lib.get_string('sprint:project', user.get_guild()).format(
                    project.get_title()))