diff options
author | Jan Hruban <jan.hruban@gooddata.com> | 2016-03-10 21:51:32 +0100 |
---|---|---|
committer | Jesse Keating <omgjlk@us.ibm.com> | 2017-05-10 14:32:02 -0700 |
commit | 570d01c5fb9aa50529e6e930f8bd9fdf2d9301bf (patch) | |
tree | 9cda78844133af41b88e8f6f1ba1238244b57e8f | |
parent | 3b415926d21b2015e0391678a004d3071c5e5915 (diff) | |
download | zuul-570d01c5fb9aa50529e6e930f8bd9fdf2d9301bf.tar.gz |
GitHub file matching support
Allow to configure jobs to run only when certain files are changed.
Github does not list the /COMMIT_MSG in the changed files as gerrit
does. Therefore the matcher now returns False only if the single file is
the /COMMIT_MSG one.
Change-Id: I4fa8a328f2ba430c25377e50e1eff7c45829eba6
-rwxr-xr-x | tests/base.py | 31 | ||||
-rw-r--r-- | tests/fixtures/layouts/files-github.yaml | 18 | ||||
-rw-r--r-- | tests/unit/test_change_matcher.py | 6 | ||||
-rw-r--r-- | tests/unit/test_github_driver.py | 16 | ||||
-rw-r--r-- | tests/unit/test_model.py | 10 | ||||
-rw-r--r-- | zuul/change_matcher.py | 4 | ||||
-rw-r--r-- | zuul/driver/github/githubconnection.py | 6 | ||||
-rw-r--r-- | zuul/driver/github/githubsource.py | 4 |
8 files changed, 84 insertions, 11 deletions
diff --git a/tests/base.py b/tests/base.py index c567b036b..937d60f18 100755 --- a/tests/base.py +++ b/tests/base.py @@ -547,7 +547,7 @@ class GithubChangeReference(git.Reference): class FakeGithubPullRequest(object): def __init__(self, github, number, project, branch, - subject, upstream_root, number_of_commits=1): + subject, upstream_root, files=[], number_of_commits=1): """Creates a new PR with several commits. Sends an event about opened PR.""" self.github = github @@ -558,6 +558,7 @@ class FakeGithubPullRequest(object): self.subject = subject self.number_of_commits = 0 self.upstream_root = upstream_root + self.files = [] self.comments = [] self.labels = [] self.statuses = {} @@ -566,18 +567,18 @@ class FakeGithubPullRequest(object): self.is_merged = False self.merge_message = None self._createPRRef() - self._addCommitToRepo() + self._addCommitToRepo(files=files) self._updateTimeStamp() - def addCommit(self): + def addCommit(self, files=[]): """Adds a commit on top of the actual PR head.""" - self._addCommitToRepo() + self._addCommitToRepo(files=files) self._updateTimeStamp() self._clearStatuses() - def forcePush(self): + def forcePush(self, files=[]): """Clears actual commits and add a commit on top of the base.""" - self._addCommitToRepo(reset=True) + self._addCommitToRepo(files=files, reset=True) self._updateTimeStamp() self._clearStatuses() @@ -690,7 +691,7 @@ class FakeGithubPullRequest(object): GithubChangeReference.create( repo, self._getPRReference(), 'refs/tags/init') - def _addCommitToRepo(self, reset=False): + def _addCommitToRepo(self, files=[], reset=False): repo = self._getRepo() ref = repo.references[self._getPRReference()] if reset: @@ -701,7 +702,12 @@ class FakeGithubPullRequest(object): zuul.merger.merger.reset_repo_to_head(repo) repo.git.clean('-x', '-f', '-d') - fn = '%s-%s' % (self.branch.replace('/', '_'), self.number) + if files: + fn = files[0] + self.files = files + else: + fn = '%s-%s' % (self.branch.replace('/', '_'), self.number) + self.files = [fn] msg = self.subject + '-' + str(self.number_of_commits) fn = os.path.join(repo.working_dir, fn) f = open(fn, 'w') @@ -776,10 +782,11 @@ class FakeGithubConnection(githubconnection.GithubConnection): self.merge_failure = False self.merge_not_allowed_count = 0 - def openFakePullRequest(self, project, branch, subject): + def openFakePullRequest(self, project, branch, subject, files=[]): self.pr_number += 1 pull_request = FakeGithubPullRequest( - self, self.pr_number, project, branch, subject, self.upstream_root) + self, self.pr_number, project, branch, subject, self.upstream_root, + files=files) self.pull_requests.append(pull_request) return pull_request @@ -830,6 +837,10 @@ class FakeGithubConnection(githubconnection.GithubConnection): } return data + def getPullFileNames(self, project, number): + pr = self.pull_requests[number - 1] + return pr.files + def getUser(self, login): data = { 'username': login, diff --git a/tests/fixtures/layouts/files-github.yaml b/tests/fixtures/layouts/files-github.yaml new file mode 100644 index 000000000..734b94545 --- /dev/null +++ b/tests/fixtures/layouts/files-github.yaml @@ -0,0 +1,18 @@ +- pipeline: + name: check + manager: independent + trigger: + github: + - event: pull_request + action: opened + +- job: + name: project-test1 + files: + - '.*-requires' + +- project: + name: org/project + check: + jobs: + - project-test1 diff --git a/tests/unit/test_change_matcher.py b/tests/unit/test_change_matcher.py index 05853223a..6b161a1e5 100644 --- a/tests/unit/test_change_matcher.py +++ b/tests/unit/test_change_matcher.py @@ -125,12 +125,18 @@ class TestMatchAllFiles(BaseTestMatcher): def test_matches_returns_false_when_not_all_files_match(self): self._test_matches(False, files=['/COMMIT_MSG', 'docs/foo', 'foo/bar']) + def test_matches_returns_true_when_single_file_does_not_match(self): + self._test_matches(True, files=['docs/foo']) + def test_matches_returns_false_when_commit_message_matches(self): self._test_matches(False, files=['/COMMIT_MSG']) def test_matches_returns_true_when_all_files_match(self): self._test_matches(True, files=['/COMMIT_MSG', 'docs/foo']) + def test_matches_returns_true_when_single_file_matches(self): + self._test_matches(True, files=['docs/foo']) + class TestMatchAll(BaseTestMatcher): diff --git a/tests/unit/test_github_driver.py b/tests/unit/test_github_driver.py index 7267b832a..605a4798d 100644 --- a/tests/unit/test_github_driver.py +++ b/tests/unit/test_github_driver.py @@ -65,6 +65,22 @@ class TestGithubDriver(ZuulTestCase): self.assertEqual(2, len(self.history)) + @simple_layout('layouts/files-github.yaml', driver='github') + def test_pull_matched_file_event(self): + A = self.fake_github.openFakePullRequest( + 'org/project', 'master', 'A', + files=['random.txt', 'build-requires']) + self.fake_github.emitEvent(A.getPullRequestOpenedEvent()) + self.waitUntilSettled() + self.assertEqual(1, len(self.history)) + + # test_pull_unmatched_file_event + B = self.fake_github.openFakePullRequest('org/project', 'master', 'B', + files=['random.txt']) + self.fake_github.emitEvent(B.getPullRequestOpenedEvent()) + self.waitUntilSettled() + self.assertEqual(1, len(self.history)) + @simple_layout('layouts/basic-github.yaml', driver='github') def test_comment_event(self): A = self.fake_github.openFakePullRequest('org/project', 'master', 'A') diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index d8480ea0a..5f968b426 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -73,11 +73,21 @@ class TestJob(BaseTestCase): change.files = ['/COMMIT_MSG', 'docs/foo'] self.assertFalse(self.job.changeMatches(change)) + def test_change_matches_returns_false_for_single_matched_skip_if(self): + change = model.Change('project') + change.files = ['docs/foo'] + self.assertFalse(self.job.changeMatches(change)) + def test_change_matches_returns_true_for_unmatched_skip_if(self): change = model.Change('project') change.files = ['/COMMIT_MSG', 'foo'] self.assertTrue(self.job.changeMatches(change)) + def test_change_matches_returns_true_for_single_unmatched_skip_if(self): + change = model.Change('project') + change.files = ['foo'] + self.assertTrue(self.job.changeMatches(change)) + def test_job_sets_defaults_for_boolean_attributes(self): self.assertIsNotNone(self.job.voting) diff --git a/zuul/change_matcher.py b/zuul/change_matcher.py index 1da1d2c5b..baea21753 100644 --- a/zuul/change_matcher.py +++ b/zuul/change_matcher.py @@ -108,7 +108,9 @@ class MatchAllFiles(AbstractMatcherCollection): yield self.commit_regex def matches(self, change): - if not (hasattr(change, 'files') and len(change.files) > 1): + if not (hasattr(change, 'files') and change.files): + return False + if len(change.files) == 1 and self.commit_regex.match(change.files[0]): return False for file_ in change.files: matched_file = False diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py index e8162cde2..0c4434fac 100644 --- a/zuul/driver/github/githubconnection.py +++ b/zuul/driver/github/githubconnection.py @@ -288,6 +288,7 @@ class GithubConnection(BaseConnection): change.url = event.change_url change.updated_at = self._ghTimestampToDate(event.updated_at) change.patchset = event.patch_number + change.files = self.getPullFileNames(project, change.number) change.title = event.title change.source_event = event elif event.ref: @@ -347,6 +348,11 @@ class GithubConnection(BaseConnection): # For now, just send back a True value. return True + def getPullFileNames(self, project, number): + owner, proj = project.name.split('/') + return [f.filename for f in + self.github.pull_request(owner, proj, number).files()] + def getUser(self, login): return GithubUser(self.github, login) diff --git a/zuul/driver/github/githubsource.py b/zuul/driver/github/githubsource.py index a63812271..312ee871a 100644 --- a/zuul/driver/github/githubsource.py +++ b/zuul/driver/github/githubsource.py @@ -84,5 +84,9 @@ class GithubSource(BaseSource): """Get the git-web url for a project.""" return self.connection.getGitwebUrl(project, sha) + def getPullFiles(self, project, number): + """Get filenames of the pull request""" + return self.connection.getPullFileNames(project, number) + def _ghTimestampToDate(self, timestamp): return time.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ') |