Example #1
0
def test_parse_vault_with_env_error(app):
    s = '''vault:
  url: http://localhost:8200
  token: abc123
  env: API_TOKEN secret/api token
'''
    f = io.StringIO(s)
    with pytest.raises(InvalidSpecification):
        Specification.parse_file(f)
Example #2
0
def test_deploy_single_provider_object_should_fail(app):
    from badwolf.exceptions import InvalidSpecification

    s = """deploy:
  script: echo test
  tag: true"""
    f = io.StringIO(s)
    with pytest.raises(InvalidSpecification):
        Specification.parse_file(f)
Example #3
0
def test_parse_image(app):
    s = """script: ls"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert not spec.image

    s = """image: python"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.image == 'python:latest'

    s = """image: python:2.7"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.image == 'python:2.7'
Example #4
0
def test_parse_docker(app):
    s = """docker: True"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.docker

    s = """docker: no"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert not spec.docker

    s = """linter: flake8"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert not spec.docker
Example #5
0
def test_parse_privileged(app):
    s = """privileged: True"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.privileged

    s = """privileged: no"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert not spec.privileged

    s = """linter: flake8"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert not spec.privileged
Example #6
0
def test_jsonlint_a_json_changes_in_range(app, pr_context):
    diff = """diff --git a/b.json b/b.json
index 6ebebfe..6be8d74 100644
--- a/b.json
+++ b/b.json
@@ -1,3 +1,4 @@
 {
     "a": 1
+    "b": 2
 }
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='jsonlint', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'jsonlint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.filename == 'b.json'
    assert problem.line == 2
Example #7
0
def test_no_changed_files_ignore(app, caplog):
    diff = """diff --git a/removed_file b/removed_file
deleted file mode 100644
index 1f38447..0000000
--- a/removed_file
+++ /dev/null
@@ -1,3 +0,0 @@
-This content shouldn't be here.
-
-This file will be removed.
"""

    context = TestContext('deepanalyzer/badwolf',
                          None,
                          'pullrequest',
                          'message', {'commit': {
                              'hash': '000000'
                          }}, {'commit': {
                              'hash': '111111'
                          }},
                          pr_id=1)
    spec = Specification()
    spec.linters.append(ObjectDict(name='flake8', pattern=None))
    lint = LintProcessor(context, spec, '/tmp')
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes:
        load_changes.return_value = patch
        lint.process()

        assert load_changes.called

    assert 'No changed files found' in caplog.text()
Example #8
0
def test_parse_file_multi_list():
    s = """script:
  - ls
  - ps
dockerfile: MyDockerfile
service:
  - redis-server
  - postgresql
after_success:
  - pwd
  - rm
after_failure:
  - echo
  - exit
notification:
  email:
    - [email protected]
    - [email protected]"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.dockerfile == 'MyDockerfile'
    assert spec.services == ['redis-server', 'postgresql']
    assert spec.scripts == ['ls', 'ps']
    assert spec.after_success == ['pwd', 'rm']
    assert spec.after_failure == ['echo', 'exit']
    assert spec.notification.emails == [
        '*****@*****.**', '*****@*****.**'
    ]
Example #9
0
def test_flake8_lint_a_py(app, pr_context):
    diff = """diff --git a/a.py b/a.py
new file mode 100644
index 0000000..fdeea15
--- /dev/null
+++ b/a.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
+
+
+def add(a, b):
+    return a+ b
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='flake8', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'flake8'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.filename == 'a.py'
    assert problem.line == 6
Example #10
0
def test_hadolint_lint_a_dockerfile(app, pr_context):
    diff = """diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..cd19857
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,3 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install file
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='hadolint', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'hadolint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 4
    problem = lint.problems[0]
    assert problem.line == 3
    assert problem.filename == 'Dockerfile'
Example #11
0
def test_stylelint_lint_a_scss(app, pr_context):
    diff = """diff --git a/a.scss b/a.scss
new file mode 100644
index 0000000..e545209
--- /dev/null
+++ b/a.scss
@@ -0,0 +1 @@
+a[id="foo"] { content: "x"; }
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='stylelint', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'stylelint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 2
    problem = lint.problems[0]
    assert problem.filename == 'a.scss'
Example #12
0
def test_rstlint_a_rst(app, pr_context):
    diff = """diff --git a/a.rst b/a.rst
new file mode 100644
index 0000000..4e46cf9
--- /dev/null
+++ b/a.rst
@@ -0,0 +1,2 @@
+Hello World
+====
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='rstlint'))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'rstlint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.filename == 'a.rst'
    assert problem.line == 2
Example #13
0
def test_bandit_lint_a_py(app, pr_context):
    diff = """diff --git a/a.py b/a.py
new file mode 100644
index 0000000..719cd56
--- /dev/null
+++ b/a.py
@@ -0,0 +1,4 @@
+try:
+    a = 1
+except Exception:
+    pass
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='bandit'))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'bandit'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.filename == 'a.py'
    assert problem.line == 3
    assert not problem.is_error
Example #14
0
def test_yamllint_a_yml(app, pr_context):
    diff = """diff --git a/a.yml b/a.yml
new file mode 100644
index 0000000..1eccee8
--- /dev/null
+++ b/a.yml
@@ -0,0 +1,3 @@
+---
+a: 1
+a: 2
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='yamllint', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'yamllint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.filename == 'a.yml'
    assert problem.line == 3
Example #15
0
def test_shellcheck_a_sh(app, pr_context):
    diff = """diff --git a/a.sh b/a.sh
new file mode 100644
index 0000000..9fb9840
--- /dev/null
+++ b/a.sh
@@ -0,0 +2 @@
+#!/bin/sh
+$foo=42
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='shellcheck', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'shellcheck'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) > 0
    problem = lint.problems[0]
    assert problem.filename == 'a.sh'
    assert problem.line == 2
Example #16
0
def test_jsonlint_a_json_changes_out_of_range(app, pr_context):
    diff = """diff --git a/c.json b/c.json
index 9b90002..c36a2a4 100644
--- a/c.json
+++ b/c.json
@@ -3,4 +3,5 @@
     "b": 2,
     c: 3,
     d: 4
+    e: 5
 }
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='jsonlint', pattern=None))
    lint = LintProcessor(pr_context, spec,
                         os.path.join(FIXTURES_PATH, 'jsonlint'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 0
Example #17
0
def test_mypy_lint_a_py(app, pr_context):
    diff = """diff --git a/a.py b/a.py
new file mode 100644
index 0000000..87604af
--- /dev/null
+++ b/a.py
@@ -0,0 +1,5 @@
+def p() -> None:
+    print('hello')
+
+
+a = p()
"""

    spec = Specification()
    spec.linters.append(ObjectDict(name='mypy', pattern=None))
    lint = LintProcessor(pr_context, spec, os.path.join(FIXTURES_PATH, 'mypy'))
    patch = PatchSet(diff.split('\n'))
    with mock.patch.object(lint, 'load_changes') as load_changes,\
            mock.patch.object(lint, 'update_build_status') as build_status,\
            mock.patch.object(lint, '_report') as report:
        load_changes.return_value = patch
        build_status.return_value = None
        report.return_value = (1, 2)
        lint.problems.set_changes(patch)
        lint.process()

        assert load_changes.called

    assert len(lint.problems) == 1
    problem = lint.problems[0]
    assert problem.line == 5
    assert problem.filename == 'a.py'
Example #18
0
    def parse_spec(self):
        '''Parse repository build/lint spec'''
        logger.info('Parsing specification for repository %s', self.context.repository)
        conf_file = os.path.join(self.context.clone_path, current_app.config['BADWOLF_PROJECT_CONF'])
        try:
            spec = Specification.parse_file(conf_file)
        except OSError:
            logger.warning(
                'No project configuration file found for repo: %s',
                self.context.repository
            )
            raise SpecificationNotFound()
        secretfile = os.path.join(self.context.clone_path, 'Secretfile')
        if os.path.exists(secretfile):
            spec.parse_secretfile(secretfile)

        branch = self.context.source['branch']['name']
        if self.context.type == 'branch' and not spec.is_branch_enabled(branch):
            logger.info(
                'Ignore tests since branch %s test is not enabled. Allowed branches: %s',
                branch,
                spec.branch
            )
            raise BuildDisabled()
        if not spec.scripts and not spec.linters:
            logger.warning('No script(s) or linter(s) to run')
            raise InvalidSpecification('No script or linter to run')
        self.spec = spec

        # setup Vault
        vault_url = spec.vault.url or current_app.config['VAULT_URL']
        vault_token = spec.vault.token or current_app.config['VAULT_TOKEN']
        if vault_url and vault_token:
            self.vault = hvac.Client(url=vault_url, token=vault_token)
            self._populate_envvars_from_vault()
Example #19
0
def test_parse_file_single_list(app):
    s = """script:
  - ls
dockerfile: MyDockerfile
service:
  - redis-server
after_success:
  - pwd
after_failure:
  - exit
notification:
  email:
    - [email protected]
  slack_webhook:
    - https://1"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.dockerfile == 'MyDockerfile'
    assert spec.services == ['redis-server']
    assert spec.scripts == ['ls']
    assert spec.after_success == ['pwd']
    assert spec.after_failure == ['exit']
    assert spec.notification.email.recipients == ['*****@*****.**']
    assert spec.notification.email.on_success == 'never'
    assert spec.notification.email.on_failure == 'always'
    assert spec.notification.slack_webhook.webhooks == ['https://1']
    assert spec.notification.slack_webhook.on_success == 'always'
    assert spec.notification.slack_webhook.on_failure == 'always'
Example #20
0
def test_parse_single_string_conf(app):
    spec = Specification.parse({
        'service': 'redis-server',
        'script': 'ls',
        'after_success': 'pwd',
        'after_failure': 'exit',
        'notification': {
            'email': {
                'recipients': '*****@*****.**',
                'on_success': 'always',
            },
            'slack_webhook': {
                'webhooks': ['https://1', 'https://2'],
                'on_failure': 'never',
            }
        }
    })
    assert spec.services == ['redis-server']
    assert spec.scripts == ['ls']
    assert spec.after_success == ['pwd']
    assert spec.after_failure == ['exit']
    assert spec.notification.email.recipients == ['*****@*****.**']
    assert spec.notification.email.on_success == 'always'
    assert spec.notification.email.on_failure == 'always'
    assert len(spec.notification.slack_webhook.webhooks) == 2
    assert spec.notification.slack_webhook.on_success == 'always'
    assert spec.notification.slack_webhook.on_failure == 'never'
Example #21
0
    def parse_spec(self):
        '''Parse repository build/lint spec'''
        logger.info('Parsing specification for repository %s',
                    self.context.repository)
        conf_file = os.path.join(self.context.clone_path,
                                 current_app.config['BADWOLF_PROJECT_CONF'])
        try:
            spec = Specification.parse_file(conf_file)
        except OSError:
            logger.warning('No project configuration file found for repo: %s',
                           self.context.repository)
            raise SpecificationNotFound()
        secretfile = os.path.join(self.context.clone_path, 'Secretfile')
        if os.path.exists(secretfile):
            spec.parse_secretfile(secretfile)

        branch = self.context.source['branch']['name']
        if self.context.type == 'branch' and not spec.is_branch_enabled(
                branch):
            logger.info(
                'Ignore tests since branch %s test is not enabled. Allowed branches: %s',
                branch, spec.branch)
            raise BuildDisabled()
        if not spec.scripts and not spec.linters:
            logger.warning('No script(s) or linter(s) to run')
            raise InvalidSpecification('No script or linter to run')
        self.spec = spec
Example #22
0
def test_parse_linter_with_regex_pattern(app):
    s = """linter: {name: "flake8", pattern: '.*\.(sls|yml|yaml)$'}"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert len(spec.linters) == 1
    linter0 = spec.linters[0]
    assert linter0.name == 'flake8'
    assert linter0.pattern == '.*\.(sls|yml|yaml)$'
Example #23
0
def test_parse_simple_linter(app):
    s = """linter: flake8"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert len(spec.linters) == 1
    linter0 = spec.linters[0]
    assert linter0.name == 'flake8'
    assert linter0.pattern is None
Example #24
0
def test_parse_empty_conf():
    spec = Specification.parse({})
    assert len(spec.scripts) == 0
    assert len(spec.services) == 0
    assert len(spec.after_success) == 0
    assert len(spec.after_failure) == 0
    assert len(spec.branch) == 0
    assert spec.dockerfile == 'Dockerfile'
    assert len(spec.notification.emails) == 0
Example #25
0
def test_parse_linter_with_pattern(app):
    s = """linter: {name: "flake8", pattern: "*.py", whatever: 123}"""
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert len(spec.linters) == 1
    linter0 = spec.linters[0]
    assert linter0.name == 'flake8'
    assert linter0.pattern == '*.py'
    assert linter0.whatever == 123
Example #26
0
def test_parse_env_single_string(app):
    s = "env: X=1 Y=2  Z=3\n"
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert len(spec.environments) == 1
    env0 = spec.environments[0]
    assert env0['X'] == '1'
    assert env0['Y'] == '2'
    assert env0['Z'] == '3'
Example #27
0
def test_parse_artifacts_paths(app):
    s = '''artifacts:
  paths:
    - dist
  excludes: __pycache__
'''
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.artifacts.paths == ['dist']
    assert spec.artifacts.excludes == ['__pycache__']
Example #28
0
def test_parse_vault_no_env(app):
    s = '''vault:
  url: http://localhost:8200
  token: abc123
'''
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert spec.vault.url == 'http://localhost:8200'
    assert spec.vault.token == 'abc123'
    assert not spec.vault.env
Example #29
0
def test_parse_secure_env(app):
    s = """env:
  - secure: {}""".format(to_text(SecureToken.encrypt('X=1 Y=2  Z=3')))
    f = io.StringIO(s)
    spec = Specification.parse_file(f)
    assert len(spec.environments) == 1
    env0 = spec.environments[0]
    assert env0['X'] == '1'
    assert env0['Y'] == '2'
    assert env0['Z'] == '3'
Example #30
0
def test_load_changes_failed_ignore(app, pr_context, caplog):
    spec = Specification()
    spec.linters.append('flake8')
    lint = LintProcessor(pr_context, spec, '/tmp')
    with mock.patch.object(lint, 'load_changes') as load_changes:
        load_changes.return_value = None
        lint.process()

        assert load_changes.called

    assert 'Load changes failed' in caplog.text