def handle_pull_request(payload): repo = payload['repository'] scm = repo['scm'] if scm.lower() != 'git': logger.info('Unsupported version system: %s', scm) return pr = payload['pullrequest'] title = pr['title'] description = pr['description'] or '' if 'ci skip' in title or 'ci skip' in description: logger.info('ci skip found, ignore tests.') return if pr['state'] != 'OPEN': logger.info('Pull request state is not OPEN, ignore tests.') return rebuild = False if 'ci rebuild' in title.lower() or 'ci rebuild' in description.lower(): rebuild = True source = pr['source'] target = pr['destination'] context = Context(repo['full_name'], payload['actor'], 'pullrequest', title, source, target, rebuild=rebuild, pr_id=pr['id']) start_pipeline.delay(context)
def handle_repo_commit_comment(payload): comment = payload['comment'] comment_content = comment['content']['raw'] retry = 'ci retry' in comment_content rebuild = 'ci rebuild' in comment_content nocache = 'no cache' in comment_content if not (retry or rebuild): return commit_hash = payload['commit']['hash'] repo = payload['repository'] repo_name = repo['full_name'] context = Context( repo_name, payload['actor'], 'commit', payload['commit']['message'], { 'repository': { 'full_name': repo_name }, 'branch': { 'name': 'master' }, 'commit': { 'hash': commit_hash }, }, rebuild=rebuild, nocache=nocache, clone_depth=0, # Force a full git clone ) start_pipeline.delay(context)
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 = Context( '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()
def handle_pull_request_comment(payload): comment = payload['comment'] comment_content = comment['content']['raw'].lower() retry = 'ci retry' in comment_content rebuild = 'ci rebuild' in comment_content cleanup_lint = 'cleanup lint' in comment_content nocache = 'no cache' in comment_content if not (retry or rebuild or cleanup_lint): return repo = payload['repository'] pr = payload['pullrequest'] title = pr['title'] if pr['state'] != 'OPEN': logger.info('Pull request state is not OPEN, ignore tests.') return source = pr['source'] target = pr['destination'] context = Context(repo['full_name'], payload['actor'], 'pullrequest', title, source, target, rebuild=rebuild, pr_id=pr['id'], cleanup_lint=cleanup_lint, nocache=nocache) start_pipeline.delay(context)
def handle_repo_push(payload): changes = payload['push']['changes'] if not changes: return repo = payload['repository'] scm = repo['scm'] if scm.lower() != 'git': logger.info('Unsupported version system: %s', scm) return for change in changes: if not change['new']: logger.info('No new changes found') continue repo_name = repo['full_name'] push_type = change['new']['type'] rebuild = False if push_type == 'tag': commit_hash = change['new']['target']['hash'] commit_message = change['new']['target']['message'] elif push_type == 'branch': if not change['commits']: logger.warning('Can not find any commits') continue commit_hash = change['commits'][0]['hash'] commit_message = change['commits'][0]['message'] if 'ci skip' in commit_message.lower(): logger.info('ci skip found, ignore tests.') continue if 'ci rebuild' in commit_message.lower(): rebuild = True else: logger.error('Unsupported push type: %s', push_type) continue source = { 'repository': {'full_name': repo_name}, 'branch': {'name': change['new']['name']}, 'commit': {'hash': commit_hash} } context = Context( repo_name, payload['actor'], push_type, commit_message, source, rebuild=rebuild, ) try: _cancel_outdated_pipelines(context) except Exception: sentry.captureException() future = start_pipeline.delay(context) future.add_done_callback(lambda fut: _RUNNING_PIPELINES.pop(context.task_id, None)) _RUNNING_PIPELINES[context.task_id] = future if push_type == 'branch': check_pr_mergeable.delay(context)
def push_context(): return Context('deepanalyzer/badwolf', {}, 'commit', 'Update', { 'repository': { 'full_name': 'deepanalyzer/badwolf' }, 'branch': { 'name': 'master' }, 'commit': { 'hash': '2cedc1af762' }, })
def handle_repo_push(payload): changes = payload['push']['changes'] if not changes: return repo = payload['repository'] scm = repo['scm'] if scm.lower() != 'git': logger.info('Unsupported version system: %s', scm) return latest_change = changes[0] if not latest_change['new'] or latest_change['new']['type'] != 'branch': logger.info('Unsupported push type: %s', latest_change['new']['type']) return if not latest_change['commits']: logger.warning('Can not find any commits') return commit_hash = latest_change['commits'][0]['hash'] commit_message = latest_change['commits'][0]['message'] if 'ci skip' in commit_message.lower(): logger.info('ci skip found, ignore tests.') return rebuild = False if 'ci rebuild' in commit_message.lower(): rebuild = True repo_name = repo['full_name'] context = Context( repo_name, payload['actor'], 'commit', commit_message, { 'repository': { 'full_name': repo_name }, 'branch': { 'name': latest_change['new']['name'] }, 'commit': { 'hash': commit_hash }, }, rebuild=rebuild, ) start_pipeline.delay(context)
def test_eslint_lint_a_js(app, caplog): diff = """diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..45e5d69 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "quotes": [2, "single"] + } +} diff --git a/a.js b/a.js new file mode 100644 index 0000000..f119a7f --- /dev/null +++ b/a.js @@ -0,0 +1 @@ +console.log("bar") """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='eslint', pattern=None)) lint = LintProcessor(context, spec, os.path.join(FIXTURES_PATH, 'eslint')) 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.js' assert problem.line == 1
def test_jscs_lint_a_js(app, caplog): diff = """diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 0000000..c287019 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,3 @@ +{ + "preset": "node-style-guide" +} \ No newline at end of file diff --git a/jscs/a.js b/a.js new file mode 100644 index 0000000..66f319a --- /dev/null +++ b/a.js @@ -0,0 +1,2 @@ +var foo = 'bar'; +if(foo === 'bar') {} """ context = Context('deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': { 'hash': '000000' }}, {'commit': { 'hash': '111111' }}, pr_id=1) spec = Specification() spec.linters.append(ObjectDict(name='jscs', pattern=None)) lint = LintProcessor(context, spec, os.path.join(FIXTURES_PATH, 'jscs')) 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 = None lint.problems.set_changes(patch) lint.process() assert load_changes.called assert len(lint.problems) == 1 problem = lint.problems[0] assert problem.filename == 'a.js' assert problem.line == 2
def test_no_linters_ignore(app): context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() lint = LintProcessor(context, spec, '/tmp') with mock.patch.object(lint, 'load_changes') as load_changes: lint.process() load_changes.assert_not_called()
def pr_context(): return Context('deepanalyzer/badwolf', None, 'pullrequest', 'message', { 'repository': { 'full_name': 'deepanalyzer/badwolf' }, 'branch': { 'name': 'master' }, 'commit': { 'hash': '000000' } }, {'commit': { 'hash': '111111' }}, pr_id=1)
def handle_pull_request(payload): repo = payload['repository'] scm = repo['scm'] if scm.lower() != 'git': logger.info('Unsupported version system: %s', scm) return pr = payload['pullrequest'] title = pr['title'] description = pr['description'] or '' if 'ci skip' in title or 'ci skip' in description: logger.info('ci skip found, ignore tests.') return if pr['state'] != 'OPEN': logger.info('Pull request state is not OPEN, ignore tests.') return title_lower = title.lower() desc_lower = description.lower() rebuild = 'ci rebuild' in title_lower or 'ci rebuild' in desc_lower skip_lint = 'lint skip' in title_lower or 'lint skip' in desc_lower source = pr['source'] target = pr['destination'] context = Context( repo['full_name'], payload['actor'], 'pullrequest', title, source, target, rebuild=rebuild, pr_id=pr['id'], skip_lint=skip_lint ) try: _cancel_outdated_pipelines(context) except Exception: sentry.captureException() future = start_pipeline.delay(context) future.add_done_callback(lambda fut: _RUNNING_PIPELINES.pop(context.task_id, None)) _RUNNING_PIPELINES[context.task_id] = future
def handle_pull_request_comment(payload): comment = payload['comment'] comment_content = comment['content']['raw'].lower() retry = 'ci retry' in comment_content rebuild = 'ci rebuild' in comment_content nocache = 'no cache' in comment_content if not (retry or rebuild): return repo = payload['repository'] pr = payload['pullrequest'] title = pr['title'] if pr['state'] != 'OPEN': logger.info('Pull request state is not OPEN, ignore tests.') return title_lower = title.lower() description = pr['description'] or '' desc_lower = description.lower() skip_lint = 'lint skip' in title_lower or 'lint skip' in desc_lower source = pr['source'] target = pr['destination'] context = Context( repo['full_name'], payload['actor'], 'pullrequest', title, source, target, rebuild=rebuild, pr_id=pr['id'], nocache=nocache, skip_lint=skip_lint ) try: _cancel_outdated_pipelines(context) except Exception: sentry.captureException() future = start_pipeline.delay(context) future.add_done_callback(lambda fut: _RUNNING_PIPELINES.pop(context.task_id, None)) _RUNNING_PIPELINES[context.task_id] = future
def test_flake8_lint_a_py(app, caplog): 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 """ context = Context( '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, 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
def test_mypy_lint_a_py(app, caplog): 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() """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='mypy', pattern=None)) lint = LintProcessor(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'
def test_bandit_lint_a_py(app, caplog): 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 """ context = Context('deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': { 'hash': '000000' }}, {'commit': { 'hash': '111111' }}, pr_id=1) spec = Specification() spec.linters.append(ObjectDict(name='bandit')) lint = LintProcessor(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 = None 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
def test_load_changes_failed_ignore(app, caplog): context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append('flake8') lint = LintProcessor(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()
def test_yamllint_a_yml(app, caplog): 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 """ context = Context('deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': { 'hash': '000000' }}, {'commit': { 'hash': '111111' }}, pr_id=1) spec = Specification() spec.linters.append(ObjectDict(name='yamllint', pattern=None)) lint = LintProcessor(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 = None 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
def test_jsonlint_a_json_changes_in_range(app, caplog): 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 } """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='jsonlint', pattern=None)) lint = LintProcessor(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
def test_shellcheck_a_sh(app, caplog): 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 """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='shellcheck', pattern=None)) lint = LintProcessor(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
def test_sasslint_lint_a_scss(app, caplog): diff = """diff --git a/a.scss b/a.scss new file mode 100644 index 0000000..48b3ebe --- /dev/null +++ b/a.scss @@ -0,0 +1,3 @@ +.test { + background-color: "#FFF" +} """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='sasslint', pattern=None)) lint = LintProcessor(context, spec, os.path.join(FIXTURES_PATH, 'sasslint')) 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) == 3 problem = lint.problems[0] assert problem.filename == 'a.scss'
def test_jsonlint_a_json_changes_out_of_range(app, caplog): 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 } """ context = Context( 'deepanalyzer/badwolf', None, 'pullrequest', 'message', {'commit': {'hash': '000000'}}, {'commit': {'hash': '111111'}}, pr_id=1 ) spec = Specification() spec.linters.append(ObjectDict(name='jsonlint', pattern=None)) lint = LintProcessor(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