Ejemplo n.º 1
0
 def _init_logger(self):
     """Initializes the Proctor logger."""
     ProctorLoggerFactory.init(
         'proctor',
         ProctorConfig.get_config_value('Proctor', 'console_log_level'),
         ProctorConfig.get_proctor_working_dir(),
         ProctorConfig.get_config_value('Proctor', 'logfile_name'))
     self._logger = ProctorLoggerFactory.getLogger()
Ejemplo n.º 2
0
 def _init_smpt():
     """Initializes the variables used to communication with the SMTP server. See Proctor's configuration file."""
     Postman._smtp_host = ProctorConfig.get_config_value(
         'SMTP', 'smtp_host')
     Postman._smtp_port = ProctorConfig.get_config_value(
         'SMTP', 'smtp_port')
     Postman._smtp_user = ProctorConfig.get_config_value(
         'SMTP', 'smtp_user')
     Postman._smtp_pwd = ProctorConfig.get_config_value('SMTP', 'smtp_pwd')
Ejemplo n.º 3
0
    def _get_project_config_value(project_name, cfg_key):
        """Returns the value of the given configuration key or None.
        :param project_name: Project being worked on, which represents a [section] name in the configuration file.
        :param cfg_key: Key for which the value is retrieved.
        :returns Value associated with the given configuration file key, or None if not found."""
        cfg_value = ProctorConfig.get_config_value(project_name, cfg_key)
        if cfg_value is None:
            new_key = f'default_{cfg_key}'
            cfg_value = ProctorConfig.get_config_value('Defaults', new_key)

        if not cfg_value is None:
            cfg_value = cfg_value.strip()

        return cfg_value  # Might be None and that's OK. Caller handles.
Ejemplo n.º 4
0
    def _refresh_student_projects(self):

        parameters = self._parse_parameters_from_argv('owner', 'emails',
                                                      'grade')
        owner = parameters['owner']
        email_file = parameters['emails']
        grade = parameters['grade']

        if owner is None and email_file is None:
            self._logger.warning(
                "Please add the --owner or --emails parameter. If both given, --owner wins."
            )
            return

        projects = ProctorConfig.get_section_items('Projects').keys()
        emails = list()
        if owner:
            emails.append(owner)
        else:
            emails = (self._get_emails_from_file(email_file))

        for p in projects:
            self._clone_project(p, emails, force=True)

        if grade:
            for p in projects:
                self._grade_project(p, emails)
Ejemplo n.º 5
0
    def get_java_classpath():
        """Determines the Java classpath use use for compilation or execution. May return None if cannot
        be determined.
        :returns Java classpath to use for compilation or execution. May return None."""

        # First, attempt to read java_classpath from the configuration file. If it's
        # not found or is empty, attempt to read the environment CLASSPATH variable.
        java_classpath = ProctorConfig.get_config_value('Defaults', 'java_classpath')
        if java_classpath is None or len(java_classpath) == 0:
            try:
                java_classpath = os.environ['CLASSPATH']
            except:
                pass
        return java_classpath
Ejemplo n.º 6
0
 def create_group(self, group_name):
     """Creates a new group on the GitLab server.
     :param group_name: Name of the group to create on the GitLab server."""
     try:
         group_path_prefix = ProctorConfig.get_config_value(
             'GitLabServer', 'group_path_prefix')
         group_path = '-'.join([group_path_prefix, group_name])
         self._server.groups.create({
             'name':
             group_name,
             'path':
             group_path,
             'visibility_level':
             gitlab.VISIBILITY_PRIVATE
         })
         self._logger.info(f"Group '{group_path}' created OK")
     except GitlabCreateError as err:
         self._logger.error(
             f'Cannot create server group {group_name}: {err.error_message}'
         )
Ejemplo n.º 7
0
 def get_junit_classpath():
     """Determines the Java classpath use use for JUnit.
     :returns Java classpath to use to run JUnit or None if it cannot be determined."""
     return ProctorConfig.get_config_value('Defaults', 'junit_path')
Ejemplo n.º 8
0
 def _init_working_dir(self):
     """Initializes the app's working directory. This is the root of all application operations."""
     self._working_dir_name = ProctorConfig.get_proctor_working_dir()
Ejemplo n.º 9
0
    def _grade_project(self, project_name=None, emails=None):
        """Grades the given project for each email in the specified email list.
        Projects are expected to have been cloned to a local directory previously.
        Results in the gradebook file saved to the project's working directory.
        :param project_name: Name of the project to grade
        :param emails: List of emails for which to clone the project"""

        if project_name is None:
            project_name = self._argsdict['project']
        project_dir = os.sep.join([self._working_dir_name, project_name])
        project_due_dt = ProctorConfig.get_config_value(project_name, 'due_dt')

        gradebook = GradeBook(self._working_dir_name, project_name,
                              project_due_dt)
        builder = Builder()
        testrunner = UnitTestRunner()
        grader = Grader(builder, testrunner, gradebook)

        owner_emails = emails if not emails is None else \
            self._get_emails_from_file(self._argsdict['emails'])
        users_missing_project = []

        self._logger.info(f'Grading {project_name}')

        num_to_grade = len(owner_emails)
        current = 0

        # Grade project for each student listed in owner_emails
        for email in owner_emails:

            email = email.strip(' ')
            current += 1

            self._logger.info('---')
            self._logger.info(f'Owner {email} ({current} of {num_to_grade})')
            if len(email) == 0:
                self._logger.debug(
                    f"Invalid owner email '{email}'. Check email file for blank lines."
                )
                continue

            dir_to_grade = Path(project_dir) / email  # interesting Path syntax
            if not dir_to_grade.exists():
                users_missing_project.append(email)
                self._logger.warning(
                    'Local project not found: {}. Try clone.'.format(
                        str(dir_to_grade)))
                gradebook.local_project_not_found(email)
                continue

            project = self._server.get_user_project(email, project_name)
            if project:
                commits = project.commits.list()
                if commits:
                    latest_commit_date = commits[
                        0].created_at  # GitLab returns most recent first (index 0)
                    grader.grade(email, project_name, dir_to_grade,
                                 project_due_dt, latest_commit_date)
                else:
                    gradebook.commit_not_found(email)
                    self._logger.warning(
                        'No commit. Server project found, no commit.')
            else:
                gradebook.server_project_not_found(email)
                self._logger.warning(
                    'Not found. Project not found on server. Check email address.'
                )

        self._logger.info('---')
        self._logger.info(f'Saving grades to: {gradebook.get_file_name()}')
        gradebook.save()

        if users_missing_project:
            self._logger.info(
                'Local project missing for: {}'.format(users_missing_project))
            if 'chide' in self._argsdict and self._argsdict['chide']:
                self._logger.info('Chiding people with missing projects...')
                Postman.send_missing_project_email(users_missing_project,
                                                   project_name, self._logger)
Ejemplo n.º 10
0
 def _init_server(self):
     """Sets the server endpoint and user token that we'll use to log in."""
     self._server = GitLabServer(
         ProctorConfig.get_config_value('GitLabServer', 'url'))
     self._user = GitLabUser(
         ProctorConfig.get_config_value('GitLabUser', 'private_token'))
Ejemplo n.º 11
0
        self._server.add_users_to_group(group_name, email_list)

    def _get_emails_from_file(self, email_file):
        """Returns a list of emails from the given file.
        :param email_file: Path to the file that contains project-owner email addresses.
        :returns: List of emails from the given email file."""
        owner_emails = GitLabUser.get_emails(email_file)
        if owner_emails is None:
            self._logger.error(
                f'EMAIL FILE {email_file} NOT FOUND. Check the path.')
        return owner_emails

    def done(self):
        # Possibly print something here
        pass


if __name__ == "__main__":

    if len(sys.argv) <= 1:
        termcolor.cprint(
            "usage: proctor.py [-h] {config, glping, clone, grade, group, srefresh}",
            color='red')
        sys.exit(-1)

    ProctorConfig.init(None)
    p = Proctor()
    p.process_command()
    p.done()
    sys.exit(0)