Esempio n. 1
0
 def test_build_raises_exception_if_parts_class_does_not_exist(
         self, mock_config, mock_parser):
     mock_config.return_value = [self._path]
     with self.assertRaises(InvalidClassError):
         Configuration('invalid_report_parts.json')
         document = DocumentController()
         document.build()
Esempio n. 2
0
class Annotations(object):
    """
    Contains the structure for generating release notes
    by collating the issue ID, release note text and business
    representative for all issues assigned to the current
    fix version which are in state done but not in state
    rejected.
    """

    CONFIGURATION = 'bio.json'
    _document_controller = None
    _document_ready = False
    _document_title = 'Sequence Annotation'

    def __init__(self):
        """ initialise the ReleaseNote object """
        self._document_controller = DocumentController(self.CONFIGURATION)

    def build_document(self):
        """ Creates the document structure """
        try:
            self._document_controller.build()
            self._document_ready = True
        except:
            self._document_ready = False
            raise

    def publish(self):
        """ publish the document """
        if not self._document_ready:
            self.build_document()
        self._document_controller.save(self._document_title + ' ' + '.docx')
Esempio n. 3
0
    def test_render(self, mock_config, mock_parser):
        mock_config.return_value = [self._path]
        Configuration('config_simple.json')
        document = DocumentController()
        self.assertIsInstance(document.configuration, Configuration)
        self.assertIsInstance(document.threadmanager, ThreadManager)
        self.assertIsInstance(document.reportmanager, ReportManager)
        self.assertIsInstance(document.partfactory, DocumentPartFactory)
        with patch('docx.document.Document.add_heading') as mock_heading, \
            patch('docx.document.Document.add_paragraph') as mock_paragraph, \
            patch('docx.document.Document.save') as mock_save:
            document.build()

        heading_calls = [
            call('Test document structure for WeeklyReport/Helicopter view',
                 0),
            call('Week 41', 1),
            call('hello world', 1),
            #call('Test title', 3),
            call('This has sub-sections', 1),
            call('this is sub section 1', 2),
            call('this is sub section 2', 2),
            call('This section uses a file path for its text', 1)
        ]
        self.assertEquals(mock_heading.call_count, len(heading_calls))
        mock_heading.assert_has_calls(heading_calls)
        self.assertEquals(17, mock_paragraph.call_count)
Esempio n. 4
0
 def test_document_raises_thread_failed_error_if_threadmanager_execute_returns_false(
         self, mock_config, mock_parser):
     mock_config.return_value = [self._path]
     Configuration('config_simple.json')
     document = DocumentController()
     with patch('pyccata.core.managers.thread.ThreadManager.execute'
                ) as mock_thread:
         mock_thread.return_value = False
         with self.assertRaises(ThreadFailedError):
             document.build()
Esempio n. 5
0
 def test_csv_with_no_file(self, mock_config_locations, mock_parse):
     self.tearDown()
     mock_config_locations.return_value = [self._path]
     with patch('pyccata.core.managers.clients.docx.Docx') as docx:
         docx.__implements__ = (ReportingInterface, )
         document = DocumentController('csv_no_file.json')
         document.build()
         csvfiles = document._thread_manager.projectmanager._client._client
         self.assertIsInstance(csvfiles, CSVClient)
         self.assertEquals(len(csvfiles), 0)
Esempio n. 6
0
 def test_report_manager_loads_document_part_factory(
         self, mock_config, mock_parser, mock_format):
     mock_config.return_value = [self._path]
     Configuration('config_sections.json')
     document = DocumentController()
     self.assertIsInstance(document.configuration, Configuration)
     self.assertIsInstance(document.threadmanager, ThreadManager)
     self.assertIsInstance(document.reportmanager, ReportManager)
     self.assertIsInstance(document.partfactory, DocumentPartFactory)
     document.format_for_email()
     self.assertEquals(1, mock_format.call_count)
Esempio n. 7
0
    def test_add_callback_hands_off_to_report_manager(self, mock_config,
                                                      mock_parser,
                                                      mock_callback):
        mock_config.return_value = [self._path]
        Configuration('config_sections.json')
        document = DocumentController()
        self.assertIsInstance(document.configuration, Configuration)
        self.assertIsInstance(document.threadmanager, ThreadManager)
        self.assertIsInstance(document.reportmanager, ReportManager)
        self.assertIsInstance(document.partfactory, DocumentPartFactory)
        document.add_callback('test', 'test_method')

        self.assertEquals(1, mock_callback.call_count)
        mock_callback.assert_called_with('test', 'test_method')
Esempio n. 8
0
 def test_thread_manager_raises_exception(self, exception, message,
                                          mock_config, mock_manager_load,
                                          mock_parser):
     mock_manager_load.side_effect = exception(message)
     mock_config.return_value = [self._path]
     Configuration('config_sections.json')
     with self.assertRaises(exception):
         DocumentController()
Esempio n. 9
0
 def test_threadmanager_raises_exception_during_initialisation(
         self, mock_threadmanager, mock_config, mock_parser):
     mock_config.return_value = [self._path]
     Configuration('config_sections.json')
     mock_threadmanager.side_effect = AttributeError(
         'Invalid attribute \'foo\' for manager ThreadManager')
     with self.assertRaises(AttributeError):
         DocumentController()
Esempio n. 10
0
 def test_report_manager_raises_invalid_module_error_if_importlib_fails(
         self, mock_import, mock_config, mock_thread, mock_report):
     mock_report.return_value = None
     mock_thread.return_value = None
     mock_config.return_value = None
     mock_import.side_effect = ImportError('Failed to load module')
     with self.assertRaises(InvalidModuleError):
         DocumentController()
Esempio n. 11
0
 def test_report_manager_raises_invalid_module_error_if_parts_module_doesnt_exist(
         self, mock_config, mock_parser):
     mock_config.return_value = [self._path]
     Configuration('config_sections.json')
     with self.assertRaises(InvalidModuleError):
         with patch('pyccata.core.factory.DocumentPartFactory.MODULE',
                    new_callable=PropertyMock) as mock_module:
             mock_module.return_value = 'pts'
             DocumentController()
Esempio n. 12
0
    def test_csv_with_broken_file(self, mock_dataframe, mock_config_locations,
                                  mock_parse):
        self.tearDown()
        mock_config_locations.return_value = [self._path]
        mock_dataframe.side_effect = DataProviders.get_csv_results()
        with patch('pyccata.core.managers.clients.docx.Docx') as docx:
            docx.__implements__ = (ReportingInterface, )
            document = DocumentController('broken_csv.json')
            document.build()
            csvfiles = document._thread_manager.projectmanager._client._client
            self.assertIsInstance(csvfiles, CSVClient)
            self.assertEquals(len(csvfiles), 0)

            document.save('Test Document.docx')
Esempio n. 13
0
    def test_csv_with_multi_file(self, mock_dataframe, mock_config_locations,
                                 mock_parse):
        mock_config_locations.return_value = [self._path]
        mock_dataframe.side_effect = DataProviders.get_csv_results()
        with patch('pyccata.core.managers.clients.docx.Docx') as docx:
            docx.__implements__ = (ReportingInterface, )
            document = DocumentController('csv_multi_file.json')
            document.build()
            self.assertEquals(
                None, document._thread_manager.projectmanager._client.server)
            self.assertIsInstance(
                document._thread_manager.projectmanager._client.projects(),
                list)
            csvfiles = document._thread_manager.projectmanager._client._client
            self.assertIsInstance(csvfiles, CSVClient)
            self.assertEquals(len(csvfiles), 2)
            for csv in csvfiles:
                self.assertIsInstance(csv._dataframe, pandas.DataFrame)
                self.assertEquals(len(csv._dataframe.index), 3)

            document.save('Test Document.docx')
Esempio n. 14
0
class ReleaseNote(object):
    """
    Contains the structure for generating release notes
    by collating the issue ID, release note text and business
    representative for all issues assigned to the current
    fix version which are in state done but not in state
    rejected.
    """

    CONFIGURATION = 'releasenote.json'
    _document_controller = None
    _document_ready = False
    _document_title = 'MSS Platform Release'

    def __init__(self):
        """ initialise the ReleaseNote object """
        self._document_controller = DocumentController(self.CONFIGURATION)

    def build_document(self):
        """ Creates the document structure """
        try:
            self._document_controller.build()
            self._document_ready = True
        except:
            self._document_ready = False
            raise

    def publish(self):
        """ publish the document """
        if not self._document_ready:
            self.build_document()

        date = datetime.strftime(datetime.now(), '%Y-%m-%d')
        self._document_controller.format_for_email()
        self._document_controller.save(self._document_title + ' ' + date +
                                       '.docx')
Esempio n. 15
0
 def __init__(self):
     """ initialise the ReleaseNote object """
     self._document_controller = DocumentController(self.CONFIGURATION)
Esempio n. 16
0
 def test_configuration_raises_exception(self, exception, message,
                                         mock_config):
     mock_config.side_effect = exception(*message)
     with self.assertRaises(exception):
         DocumentController()
Esempio n. 17
0
class ReleaseInstructions(object):
    """
    Contains the structure for generating release notes
    by collating the issue ID, release note text and business
    representative for all issues assigned to the current
    fix version which are in state done but not in state
    rejected.
    """

    CONFIGURATION = 'releaseinstructions.json'
    _document_controller = None
    _document_ready = False
    _document_title = 'MSS Platform Release Rollout and Rollback'
    _configuration = None
    _regex = re.compile(
        '^([0-9]*)?_?(\w+-\d+)_([a-zA-Z-]+)_(\w+)_(UP|DOWN)_([0-9]*)?_?(\w+)(.[a-zA-Z]+)?$',
        re.IGNORECASE
    )

    def __init__(self):
        """ initialise the ReleaseNote object """
        self._document_controller = DocumentController(self.CONFIGURATION)
        self._configuration = self._document_controller.configuration
        self._document_controller.add_callback('attachments', getattr(ReleaseInstructions, 'file_collator'))

    def build_document(self):
        """ Creates the document structure """
        try:
            self._document_controller.build()
            final = Replacements().find('FINAL').value
            if final in ['1', 'True', 'TRUE', 'true']:
                pipelines = self._document_controller.threadmanager.find('Deployment Pipelines')
                if pipelines is not None or len(pipelines) > 0:
                    for pipeline in pipelines:
                        self.pipeline_trigger(pipeline)
            self._document_ready = True
        except:
            self._document_ready = False
            raise

    def publish(self):
        """ publish the document """
        if not self._document_ready:
            self.build_document()

        date = datetime.strftime(datetime.now(), '%Y-%m-%d')
        self._document_controller.format_for_email()
        self._document_controller.save(self._document_title + ' ' + date + '.docx')

    def pipeline_trigger(self, pipeline):
        """
        Triggers a pipeline on Jenkins

        FUTURE - move out to Jenkins API wrapper
        """
        replacements = Replacements()
        pipeline = replacements.replace(pipeline)
        matches = re.search(r'(http.*\/).*', pipeline)
        if matches:
            pipeline = matches.groups(0)[0].rstrip('/')
        Logger().info('Triggering pipeline {0}'.format(pipeline))
        params = {}
        auth = (self._configuration.jenkins.user, self._configuration.jenkins.password)
        pipeline = '{0}/{1}'.format(pipeline, replacements.replace('{TRIGGER_URI}'))
        response = requests.post(pipeline, auth=auth, params=params, verify=False)
        if response.status_code != 200:
            Logger().error(
                'Error whilst triggering pipeline - server returned status {0}'.format(
                    response.status_code
                )
            )
        Logger().info('Done {0}'.format(pipeline))

    @staticmethod
    def file_collator(path, attachments):
        """
        This method unpacks all zip files and copies the resulting SQL into a temporary location

        Once complete, it repackages the temporary location and moves it into the Workspace for
        attachment to the release instruction email
        """
        Logger().info('Collating SQL files from attachments')
        package_name = Replacements().replace('mss-platform-release-{FIX_VERSION}').replace('/', '-')
        destination = os.path.join(path, package_name)
        up_dir = os.path.join(destination, 'up')
        down_dir = os.path.join(destination, 'down')
        package_dir = os.path.join(os.getcwd(), 'packages')
        if not os.path.exists(package_dir):
            create_directory(package_dir)

        create_directory(destination)
        create_directory(up_dir)
        create_directory(down_dir)

        for attachment in attachments:
            if hasattr(ReleaseInstructions, attachment.extension.lower() + '_handler'):
                filename = os.path.join(path, attachment.filename)
                Logger().debug(
                    'Calling handler \'' + attachment.extension + '_handler\' for file ' + filename
                )

                try:
                    getattr(ReleaseInstructions, attachment.extension.lower() + '_handler')(
                        destination,
                        os.path.join(path, attachment.filename)
                    )
                except Exception as exception:
                    Logger().error('Failed to add file \'' + filename + '\' to archive')
                    Logger().error('reason: ' + str(exception))

        filename = mkzip(destination, os.path.join(path, package_name + '.zip'))
        shutil.move(os.path.join(destination, filename), os.path.join(package_dir, os.path.basename(filename)))
        return os.path.basename(filename)

    @staticmethod
    def zip_handler(destination, filepath):
        temporary_directory = os.path.join(destination, 'temp')
        create_directory(temporary_directory)
        unzip(filepath, temporary_directory, flatten=True)

        sql_files = [
            filename for filename in os.listdir(
                temporary_directory
            ) if re.search(
                "^.*\.sql$", filename, re.IGNORECASE
            )
        ]
        if len(sql_files) == 0:
            Logger().error('Got zip file but it contains no SQL files. Skipping...')
        for sql in sql_files:
            ReleaseInstructions.sql_handler(destination, os.path.join(temporary_directory, sql))
        shutil.rmtree(temporary_directory)

    @staticmethod
    def sql_handler(destination, filepath):
        try:
            Logger().info('Adding file \'' + filepath + '\'')
            sql_file = ReleaseInstructions._sql_filename(os.path.basename(filepath))
            output_directory = os.path.join(
                destination,
                sql_file.direction.lower(),
                sql_file.ticket_order,
                sql_file.ticket_id,
                sql_file.server,
                sql_file.database
            )
            create_directory(output_directory)
            os.rename(
                filepath,
                os.path.join(
                    output_directory,
                    (
                        sql_file.operation_order + '_' if sql_file.operation_order is not None else ''
                    ) + sql_file.operation + '.sql'
                )
            )
        # pylint: disable=broad-except
        # We are not bothering to handle invalidly named SQL files - these will be
        # ignored from the instruction sent to SysOps.
        # ANY error here and the file gets bounced back to the developer.
        except Exception as exception:
            Logger().error('Failed to handle SQL file \'' + os.path.basename(filepath) + '\'')
            Logger().error('reason: ' +  str(exception))

    @staticmethod
    def _sql_filename(filename):
        SQLStructure = namedtuple(
            'SQLStructure',
            'ticket_order ticket_id server database direction operation_order operation'
        )

        try:
            groups = ReleaseInstructions._regex.search(filename).groups()
            return SQLStructure(
                ticket_order=(groups[0] if groups[0] != '' else 'any_order'),
                ticket_id=groups[1],
                server=groups[2],
                database=groups[3],
                direction=groups[4],
                operation_order=(groups[5] if groups[5] != '' else None),
                operation=groups[6]
            )
        except AttributeError:
            raise InvalidFilenameError('The filename \'' + filename + '\' does not match the anticipated format')
Esempio n. 18
0
 def __init__(self):
     """ initialise the ReleaseNote object """
     self._document_controller = DocumentController(self.CONFIGURATION)
     self._configuration = self._document_controller.configuration
     self._document_controller.add_callback('attachments', getattr(ReleaseInstructions, 'file_collator'))