Пример #1
0
class Redmine(object):

    def __init__(self, url, login, password, project,
                                                   custom_project_params=None):
        """ This will open redmine page, and then login

            url: your redmine url
            login: your redmine login
            password: your redmine password
            project: the id of your project
            custom_project_params: some custom parameters to pass into projects
                url, in order to create a new issue
        """
        if not url.endswith('/'):
            url += '/'
        self._url = url
        self._login = login
        self._password = password
        self._project = project
        self._custom_project_params = custom_project_params

        self._browser = Browser()
        self._do_login()

    def _do_login(self):
        self._browser.visit(self._url + LOGIN_URL)
        self._browser.fill('username', self._login)
        self._browser.fill('password', self._password)
        self._browser.find_by_name('login').first.click()

    def create_issue(self, stop_before_commit=False, **issue_fields):
        """ Create a new issue into your redmine.

        This is an awesome (crazy) method. Pay attention:

        - You need to pass at least the required fields of your redmine.
          * For instance, if my redmine requires a title, and this field has the
          name:
                'issue[subject]'

          than I must pass my title as follows:
               create_issue(subject='My name')

        - You can also pass the name of other fields you'd like to fill,
          remembering to just pass the inner content of the field's name.
          For example, in this case:
                'issue[another_field]'
          The parameter would be:
              create_issue(another_field='My content')

        - As an example, in a default Redmine, I think this are the default
          required parameters that you must pass:
              create_issue(tracker_id, subject, description, assigned_to_id,
                           start_date, due_date, estimated_hours)

        - stop_before_commit is a flag, used when you have some extra fields that
          are not yet handled by this method, so you need to deal with it by
          hand. In this cases, call this method like this:
              create_issue(do_not_commit=True)

          And the method will just fill the fields you passed, without clicking
          'commit' button.

        - IMPORTANT: Scenarios that contains custom fields are also covered.
          A custom field has its name as something like:
              'issue[custom_field_values][20]'

          In this cases, you must pass a 'custom_field_values' parameter as a dict,
          where the key is the number of the field, and the value is the content
          you want. In this example, the parameter would be as follows:
              create_issue(custom_field_values={'20': 'My content'})

          Then the method will do the rest.
        """
        new_issue_url = self._url + PROJECT_TAG + '/' + self._project + '/issues/new'
        if self._custom_project_params:
            new_issue_url += '?%s' % self._custom_project_params
        self._browser.visit(new_issue_url)

        def fill_custom_field(field_id, field_value):
            for custom_field_number, custom_field_value in field_value.items():
                self._browser.fill(ISSUE_TAG + '[%s][%s]' % (field_id,
                    custom_field_number), custom_field_value)
        for field_id, field_value in issue_fields.items():
            if type(field_value) == type({}):
                fill_custom_field(field_id, field_value)
            else:
                self._browser.fill(ISSUE_TAG + '[%s]' % field_id, field_value)

        if not stop_before_commit:
            self._browser.find_by_name('commit').first.click()
        # TODO: find 'task_id' to return
        # (the last number under page url may be this)

    def fill_time(self, issue_id, start_date, end_date, time_per_day):
        """ Fill time into some issue that already exists.

            issue_id: id of the existing issue
            start_date: date to start filling in time
            end_date: date to end filling in time (self-including)

        - Pass start and end date as YYYY-MM-DD format, like on this example:

            fill_time(1, start_date="2011-04-23", end_date="2011-04-27", 4)

          Following this example, after method is run, the issue with id '1'
          will have, from monday to friday (2011/04/23, 2011/04/27), a new
          working time, with value 4 (4 hours), with a total of 20 hours worked
          on the week.
        """
        def discover_working_days(start_date, end_date, time_per_day):
            # format date
            start_date = strptime(start_date, '%Y-%m-%d')
            end_date = strptime(end_date, '%Y-%m-%d')
            # convert date to datetime
            start_date = datetime.date(start_date.tm_year, start_date.tm_mon,
                                                             start_date.tm_mday)
            end_date = datetime.date(end_date.tm_year, end_date.tm_mon,
                                                               end_date.tm_mday)

            working_days = []
            total_number_of_days = (end_date - start_date).days + 1

            current_date = start_date
            for day in range(total_number_of_days):
                if current_date.isoweekday() in range(1, 6): # working day [1,2,3,4,5]
                    date = current_date.strftime('%Y-%m-%d')
                    working_days.append((date, time_per_day))
                current_date = datetime.timedelta(days=1) + current_date

            return working_days

        working_days = discover_working_days(start_date, end_date, time_per_day)
        # like: [("2011-03-14", 4), ("2011-03-15", 4), .....]

        new_time_url = self._url + ISSUE_TAG + 's/' + issue_id + '/' + TIME_URL
        for date, hour in working_days:
            self._browser.visit(new_time_url)
            self._browser.fill(TIME_TAG + '[spent_on]', str(date)) # "2011-03-14"
            self._browser.fill(TIME_TAG + '[hours]', str(hour))
            self._browser.find_by_name('commit').first.click()

    def close_issue(self, issue_id):
        issue_url = ISSUE_TAG + 's/' + issue_id
        self._browser.open(self._url + issue_url)
        self._browser.find_link_by_partial_href(issue_url + '/edit').first.click()
        self._browser.select(ISSUE_TAG + '[done_ratio]', "label=100 %")
        self._browser.select(ISSUE_TAG + '[status_id]', "label=Resolvido")
        self._browser.find_by_name('commit').first.click()