def setUp(self):
     self.host = 'http://localhost'
     self.port = '9000'
     self.user = '******'
     self.password = '******'
     self.test_group = str(uuid.uuid1())
     username = str(uuid.uuid1())
     self.sonar = SonarAPIHandler(user=self.user, password=self.password)
     self.test_user = self.sonar.create_user(
         username, 'qwerty', username,
         "{}@example.com".format(username)).json().get('user')
def main():
    """
    Manage a SonarQube's groups, using a
    SonarAPIHandler connected to the given host.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(host=options.host,
                        port=options.port,
                        user=options.user,
                        password=options.password,
                        token=options.authtoken,
                        base_path=options.basepath)

    if options.command == 'list':
        groups = h.get_groups(options.fields, options.query).json()
        table = PrettyTable(
            ['ID', 'Name', 'Description', 'Members', 'Default'])
        for group in groups['groups']:
            table.add_row([
                group.get('id'),
                group.get('name'),
                group.get('description'),
                group.get('membersCount'),
                group.get('default')
            ])
        print(table)
    elif options.command == 'create':
        res = h.create_group(options.name, options.description).json()
        print(res['group'])
    elif options.command == 'update':
        res = h.update_group(options.gid, options.name,
                             options.description).json()
        print(res['group'])
    elif options.command == 'delete':
        res = h.delete_group(options.gid, options.name)
        if res.status_code == 204:
            print("Group was successfully deleted")
        else:
            print("Error[%s] %s" % (res.status_code, res.reason))
    elif options.command == 'add-user':
        res = h.add_user_group(options.login, options.gid, options.name)
        if res.status_code == 204:
            print("User was successfully added")
        else:
            print("Error[%s] %s" % (res.status_code, res.reason))
    elif options.command == 'remove-user':
        res = h.remove_user_group(options.login, options.gid, options.name)
        if res.status_code == 204:
            print("User was successfully removed")
        else:
            print("Error[%s] %s" % (res.status_code, res.reason))
    elif options.command == 'list-users':
        users = h.get_group_users(options.gid, options.name,
                                  options.query).json()
        table = PrettyTable(['Login', 'Name'])
        for user in users['users']:
            table.add_row([user['login'], user['name']])
        print(table)
def main():
    """
    Activate rules in a profile using a SonarAPIHandler instance.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(
        host=options.host,
        port=options.port,
        user=options.user,
        password=options.password,
        token=options.authtoken,
        base_path=options.basepath,
    )

    # Counters (total, created, skipped and failed)
    a, f = 0, 0

    # Read file and import
    try:
        with open(options.filename, "r") as import_file:
            # Init reader and check headers
            reader = csv.DictReader(import_file)

            # Iterate rules and try to import them
            for rule_def in reader:
                key = rule_def.pop("key", None)
                try:
                    # Pop key, clean data and attempt activation
                    rule_def["reset"] = rule_def.get("reset", "").lower() in ("y", "yes", "true")
                    rule_def = {k: v for k, v in rule_def.items() if v}
                    h.activate_rule(key, options.profile_key, **rule_def)
                    a += 1

                except ValidationError as e:
                    # Invalid data, print error
                    sys.stderr.write("Failed to activate rule {}: " "{}\n".format(key, e))
                    f += 1

    except Exception as e:
        # Other errors, stop execution immediately
        sys.stderr.write("Error: {}\n".format(e))
        status = "Incomplete"

    else:
        # No errors, write result
        status = "Complete"

    # Finally, write results
    sys.stdout.write("{} rules activation: {} activated and " "{} failed.\n".format(status, a, f))
예제 #4
0
def main():
    """
    Activate rules in a profile using a SonarAPIHandler instance.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(host=options.host, port=options.port,
                        user=options.user, password=options.password,
                        token=options.authtoken, base_path=options.basepath)

    # Counters (total, created, skipped and failed)
    a, f = 0, 0

    # Read file and import
    try:
        with open(options.filename, 'r') as import_file:
            # Init reader and check headers
            reader = csv.DictReader(import_file)

            # Iterate rules and try to import them
            for rule_def in reader:
                key = rule_def.pop('key', None)
                try:
                    # Pop key, clean data and attempt activation
                    rule_def['reset'] = rule_def.get('reset', '').lower() in ('y', 'yes', 'true')
                    rule_def = {k: v for k, v in rule_def.items() if v}
                    h.activate_rule(key, options.profile_key, **rule_def)
                    a += 1

                except ValidationError as e:
                    # Invalid data, print error
                    sys.stderr.write("Failed to activate rule {}: "
                                     "{}\n".format(key, e))
                    f += 1

    except Exception as e:
        # Other errors, stop execution immediately
        sys.stderr.write("Error: {}\n".format(e))
        status = 'Incomplete'

    else:
        # No errors, write result
        status = 'Complete'

    # Finally, write results
    sys.stdout.write("{} rules activation: {} activated and "
                     "{} failed.\n".format(status, a, f))
def main():
    """
    Activate rules in a profile using a SonarAPIHandler instance.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(options.host, options.port,
                        options.user, options.password)

    # Counters (total, created, skipped and failed)
    a, f = 0, 0

    # Read file and import
    try:
        with open(options.filename, 'r') as import_file:
            # Init reader and check headers
            reader = csv.DictReader(import_file)

            # Iterate rules and try to import them
            for rule_def in reader:
                key = rule_def.pop('key', None)
                try:
                    # Pop key, clean data and attempt activation
                    rule_def['reset'] = rule_def.get('reset', '').lower() in ('y', 'yes', 'true')
                    rule_def = {k: v for k, v in rule_def.items() if v}
                    h.activate_rule(key, options.profile_key, **rule_def)
                    a += 1

                except ValidationError as e:
                    # Invalid data, print error
                    sys.stderr.write("Failed to activate rule {}: "
                                     "{}\n".format(key, e))
                    f += 1

    except Exception as e:
        # Other errors, stop execution immediately
        sys.stderr.write("Error: {}\n".format(e))
        status = 'Incomplete'

    else:
        # No errors, write result
        status = 'Complete'

    # Finally, write results
    sys.stdout.write("{} rules activation: {} activated and "
                     "{} failed.\n".format(status, a, f))
예제 #6
0
def main():
    """
    Manage a SonarQube's users, using a
    SonarAPIHandler connected to the given host.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(host=options.host,
                        port=options.port,
                        user=options.user,
                        password=options.password,
                        token=options.authtoken,
                        base_path=options.basepath)

    if options.command == 'list':
        users = h.get_users(options.logins, options.deactivated).json()
        table = PrettyTable(['Login', 'Name', 'Email', 'Groups', 'Active'])
        for user in users['users']:
            table.add_row([
                user.get('login'),
                user.get('name'),
                user.get('email'),
                user.get('groups'),
                user.get('active')
            ])
        print(table)
    elif options.command == 'create':
        res = h.create_user(options.login, options.user_pass, options.name,
                            options.email).json()
        print(res['user'])
    elif options.command == 'update':
        res = h.update_user(options.login, options.name, options.email).json()
        print(res['user'])
    elif options.command == 'deactivate':
        res = h.deactivate_user(options.login).json()
        print(res['user'])
예제 #7
0
    def test_main(self, post_mock, parse_mock, stderr_mock, stdout_mock,
                  open_mock):
        # Set call arguments
        parse_mock.return_value = mock.MagicMock(host='localhost',
                                                 port='9000',
                                                 user='******',
                                                 password='******',
                                                 profile_key='py-234345',
                                                 filename='active-rules.csv')

        # Mock file handlers
        csv_file = StringIO(
            # Headers
            u'key,reset,severity,xpathQuery,message,format\n'
            # Standard rules: only reset first three
            'pylint:123,yes,,,,\n'
            'pylint:234,TRUE,,,,\n'
            'pylint:345,Y,,,,\n'
            'pylint:346,,,,,\n'
            # Customized rule: set severity and format
            'S123,,major,,,^foo|bar$\n'
            # Custom rule: set severity, xpath and message
            'X123,no,BLOCKER,\lala,Do not use lala,\n'
            # Error: incorrect severity
            'X123,no,so-so,\lala,Do not use lala,\n')
        open_mock.return_value = csv_file

        # Set data to receive from server
        post_mock.side_effect = [
            # First fix rules OK
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            # Sixth rule wrong: bad severity
            mock.MagicMock(
                status_code=400,
                json=mock.MagicMock(
                    return_value={
                        'errors': [{
                            'msg':
                            "Value of parameter 'severity' (SO-SO) "
                            "must be one of: [INFO, MINOR, MAJOR, CRITICAL, BLOCKER]."
                        }]
                    })),
        ]

        # Execute command
        activate_rules.main()

        # Check post calls
        # Note: check by one to ease debugging
        h = SonarAPIHandler(host='localhost',
                            port='9000',
                            user='******',
                            password='******')
        url = h._get_url(h.RULES_ACTIVATION_ENDPOINT)
        self.assertEqual(
            post_mock.mock_calls[0],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'pylint:123',
                          'reset': 'true'
                      }))
        self.assertEqual(
            post_mock.mock_calls[1],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'pylint:234',
                          'reset': 'true'
                      }))
        self.assertEqual(
            post_mock.mock_calls[2],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'pylint:345',
                          'reset': 'true'
                      }))
        self.assertEqual(
            post_mock.mock_calls[3],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'pylint:346',
                          'reset': 'false'
                      }))
        self.assertEqual(
            post_mock.mock_calls[4],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'S123',
                          'reset': 'false',
                          'severity': 'MAJOR',
                          'params': 'format=^foo|bar$'
                      }))
        self.assertEqual(
            post_mock.mock_calls[5],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'X123',
                          'reset': 'false',
                          'severity': 'BLOCKER',
                          'params': 'message=Do not use lala;xpathQuery=\\lala'
                      }))
        self.assertEqual(
            post_mock.mock_calls[6],
            mock.call(url,
                      data={
                          'profile_key': 'py-234345',
                          'rule_key': 'X123',
                          'reset': 'false',
                          'severity': 'SO-SO',
                          'params': 'message=Do not use lala;xpathQuery=\\lala'
                      }))

        # Check error calls
        stderr_mock.write.assert_called_once_with(
            "Failed to activate rule X123: Value of parameter 'severity' "
            "(SO-SO) must be one of: [INFO, MINOR, MAJOR, CRITICAL, BLOCKER].\n"
        )

        # Check stdout write: 3 exported and 1 failed
        stdout_mock.write.assert_called_once_with(
            'Complete rules activation: 6 activated and 1 failed.\n')
def main():
    """
    Migrate custom rules from one server to another one using two
    SonarAPIHandler instances.
    """
    options = parser.parse_args()
    sh = SonarAPIHandler(host=options.source_host, port=options.source_port,
                         user=options.source_user, password=options.source_password,
                         token=options.source_authtoken, base_path=options.source_basepath)
    th = SonarAPIHandler(host=options.target_host, port=options.target_port,
                         user=options.target_user, password=options.target_password,
                         token=options.target_authtoken, base_path=options.target_basepath)

    # Get the generator of source rules
    rules = sh.get_rules(active_only=True, custom_only=True)

    # Counters (total, created, skipped and failed)
    c, s, f = 0, 0, 0

    # Now import and keep count
    try:
        for rule in rules:
            # Ensure we have params (only custom rules have them)
            params = rule.get('params')
            if params:
                # Ok, let's try to create it
                try:
                    # Get key, message, and xpath params
                    key = rule['key'].split(':')[-1]
                    message = None
                    xpath = None
                    for p in params:
                        if p['key'] == 'message':
                            message = p['defaultValue']
                        elif p['key'] == 'xpathQuery':
                            xpath = p['defaultValue']

                    # Now create it and increase counter
                    th.create_rule(key, rule['name'], rule['mdDesc'], message,
                                   xpath, rule['severity'], rule['status'],
                                   rule['templateKey'])
                    c += 1

                except ValidationError as e:
                    # Validation error, should continue execution afterwards
                    if 'already exists' in str(e):
                        # Rule already exists, skip
                        s += 1

                    else:
                        # Invalid data for rule creation, fail
                        f += 1
                        sys.stderr.write("Failed to create rule {}: "
                                         "{}\n".format(rule['key'], e))

    except Exception as e:
        # Other errors, stop execution immediately
        sys.stderr.write("Error: {}\n".format(e))
        status = 'Incomplete'

    else:
        # No errors, write result
        status = 'Complete'

    # Finally, write results
    sys.stdout.write("{} rules migration: {} created, {} skipped (already "
                     "existing) and {} failed.\n".format(status, c, s, f))
class GroupsTest(TestCase):
    def setUp(self):
        self.host = 'http://localhost'
        self.port = '9000'
        self.user = '******'
        self.password = '******'
        self.test_group = str(uuid.uuid1())
        username = str(uuid.uuid1())
        self.sonar = SonarAPIHandler(user=self.user, password=self.password)
        self.test_user = self.sonar.create_user(
            username, 'qwerty', username,
            "{}@example.com".format(username)).json().get('user')

    # List
    @mock.patch('sonarqube_api.cmd.users.argparse.ArgumentParser.parse_args')
    def test_cmd_list_groups(self, parse_mock):
        parse_mock.return_value = argparse.Namespace(host=self.host,
                                                     port=self.port,
                                                     user=self.user,
                                                     password=self.password,
                                                     authtoken=None,
                                                     basepath=None,
                                                     command='list',
                                                     fields=None,
                                                     query=None)
        groups.main()

    # Create
    @mock.patch('sonarqube_api.cmd.users.argparse.ArgumentParser.parse_args')
    def test_cmd_create_group(self, parse_mock):
        parse_mock.return_value = argparse.Namespace(host=self.host,
                                                     port=self.port,
                                                     user=self.user,
                                                     password=self.password,
                                                     authtoken=None,
                                                     basepath=None,
                                                     command='create',
                                                     name=self.test_group,
                                                     description=None)
        groups.main()

    # Update and delete
    @mock.patch('sonarqube_api.cmd.users.argparse.ArgumentParser.parse_args')
    def test_cmd_update_delete_group(self, parse_mock):
        res = self.sonar.create_group(str(uuid.uuid1())).json()
        parse_mock.return_value = argparse.Namespace(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            authtoken=None,
            basepath=None,
            command='update',
            gid=res['group']['id'],
            name=None,
            description='Awesome group')
        groups.main()

        parse_mock.return_value = argparse.Namespace(host=self.host,
                                                     port=self.port,
                                                     user=self.user,
                                                     password=self.password,
                                                     authtoken=None,
                                                     basepath=None,
                                                     command='delete',
                                                     gid=res['group']['id'],
                                                     name=None)
        groups.main()

    # Add and remove user
    @mock.patch('sonarqube_api.cmd.users.argparse.ArgumentParser.parse_args')
    def test_cmd_add_remove_user_group(self, parse_mock):
        res = self.sonar.create_group(str(uuid.uuid1())).json()
        parse_mock.return_value = argparse.Namespace(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            authtoken=None,
            basepath=None,
            command='add-user',
            login=self.test_user['login'],
            name=res['group']['name'],
            gid=None)
        groups.main()

        parse_mock.return_value = argparse.Namespace(
            host=self.host,
            port=self.port,
            user=self.user,
            password=self.password,
            authtoken=None,
            basepath=None,
            command='remove-user',
            login=self.test_user['login'],
            name=res['group']['name'],
            gid=None)
        groups.main()
        self.sonar.delete_group(name=res['group']['name'])

    # List users
    @mock.patch('sonarqube_api.cmd.users.argparse.ArgumentParser.parse_args')
    def test_cmd_list_users_group(self, parse_mock):
        res = self.sonar.create_group(str(uuid.uuid1())).json()
        self.sonar.add_user_group(self.test_user['login'],
                                  name=res['group']['name'])
        parse_mock.return_value = argparse.Namespace(host=self.host,
                                                     port=self.port,
                                                     user=self.user,
                                                     password=self.password,
                                                     authtoken=None,
                                                     basepath=None,
                                                     command='list-users',
                                                     name=res['group']['name'],
                                                     gid=None,
                                                     query=None)
        groups.main()
        self.sonar.delete_group(name=res['group']['name'])
예제 #10
0
def main():
    """
    Export a SonarQube's rules to a CSV and an HTML file, using a
    SonarAPIHandler connected to the given host.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(options.host, options.port, options.user, options.password)

    # Determine output csv and html file names
    csv_fn = os.path.expanduser(os.path.join(options.output, 'rules.csv'))
    html_fn = os.path.expanduser(os.path.join(options.output, 'rules.html'))

    # Open csv and html files
    with open(csv_fn, 'w') as csv_f, open(html_fn, 'w') as html_f:
        # Init csv writer and write header
        csv_w = csv.writer(csv_f)
        csv_w.writerow(['language', 'key', 'name', 'debt', 'severity'])

        # Start html file
        html_f.write(u'<html><body>')

        # Get the rules generator
        rules = h.get_rules(options.active,
                            options.profile,
                            options.languages)

        # Counters (total, exported and failed)
        s, f = 0, 0

        # Now import and keep count
        try:
            for rule in rules:
                try:
                    # Write CSV row
                    csv_w.writerow([
                        rule['langName'],
                        rule['key'],
                        rule['name'],
                        # Note: debt can be in diff. fields depending on type
                        rule.get('debtRemFnOffset',
                                 rule.get('debtRemFnCoeff', u'-')),
                        rule['severity']
                    ])

                    # Render parameters sublist
                    params_htmls = []
                    if rule['params']:
                        for param in rule['params']:
                            params_htmls.append(u'<li>{}: {}</li>'.format(
                                param.get('key', u'-'),
                                param.get('defaultValue', u'-')
                            ))
                    else:
                        params_htmls.append(u'-')

                    # Build values to write in html
                    values = (
                        rule['key'], rule['name'], rule['langName'],
                        rule['key'], rule['severity'],
                        rule.get('debtRemFnOffset', rule.get('debtRemFnCoeff', u'-')),
                        u''.join(params_htmls), rule.get('htmlDesc', u'-')
                    )

                    # Render html and write to file
                    html = utf_encode(HTML_RULE_TEMPLATE.format(*values))
                    html_f.write(html)
                    s += 1

                except KeyError as exc:
                    # Key error, should continue execution afterwards
                    sys.stderr.write("Error: missing values for {}\n".format(','.join(exc.args)))
                    f += 1

            # Done with rules, close html body and document
            html_f.write(u'</body></html>')

        except Exception as exc:
            # Other errors, stop execution immediately
            sys.stderr.write("Error: {}\n".format(exc))
            status = 'Incomplete'

        else:
            # No errors, complete
            status = 'Complete'

        # Finally, write results
        sys.stdout.write("{} rules export: {} exported and "
                         "{} failed.\n".format(status, s, f))
예제 #11
0
    def test_main(self, post_mock, parse_mock, stderr_mock,
                  stdout_mock, open_mock):
        # Set call arguments
        parse_mock.return_value = mock.MagicMock(
            host='localhost', port='9000', user='******', password='******',
            profile_key='py-234345', filename='active-rules.csv', basepath=None
        )

        # Mock file handlers
        csv_file = StringIO(
            # Headers
            u'key,reset,severity,xpathQuery,message,format\n'
            # Standard rules: only reset first three
            'pylint:123,yes,,,,\n'
            'pylint:234,TRUE,,,,\n'
            'pylint:345,Y,,,,\n'
            'pylint:346,,,,,\n'
            # Customized rule: set severity and format
            'S123,,major,,,^foo|bar$\n'
            # Custom rule: set severity, xpath and message
            'X123,no,BLOCKER,\lala,Do not use lala,\n'
            # Error: incorrect severity
            'X123,no,so-so,\lala,Do not use lala,\n'
        )
        open_mock.return_value = csv_file

        # Set data to receive from server
        post_mock.side_effect = [
            # First fix rules OK
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            mock.MagicMock(status_code=200),
            # Sixth rule wrong: bad severity
            mock.MagicMock(status_code=400, json=mock.MagicMock(return_value={'errors': [{
                    'msg': "Value of parameter 'severity' (SO-SO) "
                           "must be one of: [INFO, MINOR, MAJOR, CRITICAL, BLOCKER]."
            }]})),
        ]

        # Execute command
        activate_rules.main()

        # Check post calls
        # Note: check by one to ease debugging
        h = SonarAPIHandler(host='localhost', port='9000', user='******', password='******')
        url = h._get_url(h.RULES_ACTIVATION_ENDPOINT)
        self.assertEqual(post_mock.mock_calls[0], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'pylint:123', 'reset': 'true'}
        ))
        self.assertEqual(post_mock.mock_calls[1], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'pylint:234', 'reset': 'true'}
        ))
        self.assertEqual(post_mock.mock_calls[2], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'pylint:345', 'reset': 'true'}
        ))
        self.assertEqual(post_mock.mock_calls[3], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'pylint:346', 'reset': 'false'}
        ))
        self.assertEqual(post_mock.mock_calls[4], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'S123', 'reset': 'false',
                       'severity': 'MAJOR', 'params': 'format=^foo|bar$'}
        ))
        self.assertEqual(post_mock.mock_calls[5], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'X123', 'reset': 'false',
                       'severity': 'BLOCKER', 'params': 'message=Do not use lala;xpathQuery=\\lala'}
        ))
        self.assertEqual(post_mock.mock_calls[6], mock.call(
            url, data={'profile_key': 'py-234345', 'rule_key': 'X123', 'reset': 'false',
                       'severity': 'SO-SO', 'params': 'message=Do not use lala;xpathQuery=\\lala'}
        ))

        # Check error calls
        stderr_mock.write.assert_called_once_with(
            "Failed to activate rule X123: Value of parameter 'severity' "
            "(SO-SO) must be one of: [INFO, MINOR, MAJOR, CRITICAL, BLOCKER].\n"
        )

        # Check stdout write: 3 exported and 1 failed
        stdout_mock.write.assert_called_once_with('Complete rules activation: 6 activated and 1 failed.\n')
예제 #12
0
def main():
    """
    Migrate custom rules from one server to another one using two
    SonarAPIHandler instances.
    """
    options = parser.parse_args()
    sh = SonarAPIHandler(host=options.source_host,
                         port=options.source_port,
                         user=options.source_user,
                         password=options.source_password,
                         token=options.source_authtoken,
                         base_path=options.source_basepath)
    th = SonarAPIHandler(host=options.target_host,
                         port=options.target_port,
                         user=options.target_user,
                         password=options.target_password,
                         token=options.target_authtoken,
                         base_path=options.target_basepath)

    # Get the generator of source rules
    rules = sh.get_rules(active_only=True, custom_only=True)

    # Counters (total, created, skipped and failed)
    c, s, f = 0, 0, 0

    # Now import and keep count
    try:
        for rule in rules:
            # Ensure we have params (only custom rules have them)
            params = rule.get('params')
            if params:
                # Ok, let's try to create it
                try:
                    # Get key, message, and xpath params
                    key = rule['key'].split(':')[-1]
                    message = None
                    xpath = None
                    for p in params:
                        if p['key'] == 'message':
                            message = p['defaultValue']
                        elif p['key'] == 'xpathQuery':
                            xpath = p['defaultValue']

                    # Now create it and increase counter
                    th.create_rule(key, rule['name'], rule['mdDesc'], message,
                                   xpath, rule['severity'], rule['status'],
                                   rule['templateKey'])
                    c += 1

                except ValidationError as e:
                    # Validation error, should continue execution afterwards
                    if 'already exists' in str(e):
                        # Rule already exists, skip
                        s += 1

                    else:
                        # Invalid data for rule creation, fail
                        f += 1
                        sys.stderr.write("Failed to create rule {}: "
                                         "{}\n".format(rule['key'], e))

    except Exception as e:
        # Other errors, stop execution immediately
        sys.stderr.write("Error: {}\n".format(e))
        status = 'Incomplete'

    else:
        # No errors, write result
        status = 'Complete'

    # Finally, write results
    sys.stdout.write("{} rules migration: {} created, {} skipped (already "
                     "existing) and {} failed.\n".format(status, c, s, f))
예제 #13
0
def main():
    """
    Export a SonarQube's rules to a CSV and an HTML file, using a
    SonarAPIHandler connected to the given host.
    """
    options = parser.parse_args()
    h = SonarAPIHandler(options.host, options.port, options.user,
                        options.password)

    # Determine output csv and html file names
    csv_fn = os.path.expanduser(os.path.join(options.output, 'rules.csv'))
    html_fn = os.path.expanduser(os.path.join(options.output, 'rules.html'))

    # Open csv and html files
    with open(csv_fn, 'w') as csv_f, open(html_fn, 'w') as html_f:
        # Init csv writer and write header
        csv_w = csv.writer(csv_f)
        csv_w.writerow(['language', 'key', 'name', 'debt', 'severity'])

        # Start html file
        html_f.write(u'<html><body>')

        # Get the rules generator
        rules = h.get_rules(options.active, options.profile, options.languages)

        # Counters (total, exported and failed)
        s, f = 0, 0

        # Now import and keep count
        try:
            for rule in rules:
                try:
                    # Write CSV row
                    csv_w.writerow([
                        rule['langName'],
                        rule['key'],
                        rule['name'],
                        # Note: debt can be in diff. fields depending on type
                        rule.get('debtRemFnOffset',
                                 rule.get('debtRemFnCoeff', u'-')),
                        rule['severity']
                    ])

                    # Render parameters sublist
                    params_htmls = []
                    if rule['params']:
                        for param in rule['params']:
                            params_htmls.append(u'<li>{}: {}</li>'.format(
                                param.get('key', u'-'),
                                param.get('defaultValue', u'-')))
                    else:
                        params_htmls.append(u'-')

                    # Build values to write in html
                    values = (rule['key'], rule['name'], rule['langName'],
                              rule['key'], rule['severity'],
                              rule.get('debtRemFnOffset',
                                       rule.get('debtRemFnCoeff',
                                                u'-')), u''.join(params_htmls),
                              rule.get('htmlDesc', u'-'))

                    # Render html and write to file
                    html = utf_encode(HTML_RULE_TEMPLATE.format(*values))
                    html_f.write(html)
                    s += 1

                except KeyError as exc:
                    # Key error, should continue execution afterwards
                    sys.stderr.write("Error: missing values for {}\n".format(
                        ','.join(exc.args)))
                    f += 1

            # Done with rules, close html body and document
            html_f.write(u'</body></html>')

        except Exception as exc:
            # Other errors, stop execution immediately
            sys.stderr.write("Error: {}\n".format(exc))
            status = 'Incomplete'

        else:
            # No errors, complete
            status = 'Complete'

        # Finally, write results
        sys.stdout.write("{} rules export: {} exported and "
                         "{} failed.\n".format(status, s, f))