Title: [291619] trunk/Tools
Revision
291619
Author
jbed...@apple.com
Date
2022-03-22 08:25:30 -0700 (Tue, 22 Mar 2022)

Log Message

[Merge-Queue] Add ValidateCommitterAndReviewer
https://bugs.webkit.org/show_bug.cgi?id=238150
<rdar://problem/90587620>

Reviewed by Aakash Jain.

* Tools/CISupport/ews-build/factories.py:
(CommitQueueFactory.__init__): Rename ValidateCommiterAndReviewer to ValidateCommiterAndReviewer.
(MergeQueueFactory.__init__): Add ValidateCommitterAndReviewer, PrintConfiguration, CleanGitRepo,
CheckOutSource, FetchBranches, ShowIdentifier, VerifyGitHubIntegrity, UpdateWorkingDirectory
and CheckOutPullRequest.
* Tools/CISupport/ews-build/factories_unittest.py:
(TestExpectedBuildSteps): Add Merge-Queue step names.
* Tools/CISupport/ews-build/steps.py:
(GitHubMixin.get_pr_json): Retry tied to attempt not index.
(GitHubMixin.get_reviewers): Get list of reviewers for pull-request in repository.
(ValidateCommitterAndReviewer): Renamed from ValidateCommiterAndReviewer, inherit from GitHubMixin.
(ValidateCommitterAndReviewer.__init__): Rename ValidateCommiterAndReviewer.
(ValidateCommitterAndReviewer.fail_build): Block pull request, differentiate comment for pull
request and patch.
(ValidateCommitterAndReviewer.start): Support pull requests.
(ValidateCommiterAndReviewer): Renamed to ValidateCommitterAndReviewer.
* Tools/CISupport/ews-build/steps_unittest.py:

Canonical link: https://commits.webkit.org/248712@main

Modified Paths

Diff

Modified: trunk/Tools/CISupport/ews-build/factories.py (291618 => 291619)


--- trunk/Tools/CISupport/ews-build/factories.py	2022-03-22 15:24:09 UTC (rev 291618)
+++ trunk/Tools/CISupport/ews-build/factories.py	2022-03-22 15:25:30 UTC (rev 291619)
@@ -32,7 +32,7 @@
                    RunEWSUnitTests, RunResultsdbpyTests, RunJavaScriptCoreTests, RunWebKit1Tests, RunWebKitPerlTests, RunWebKitPyPython2Tests,
                    RunWebKitPyPython3Tests, RunWebKitTests, RunWebKitTestsRedTree, RunWebKitTestsInStressMode, RunWebKitTestsInStressGuardmallocMode,
                    SetBuildSummary, ShowIdentifier, TriggerCrashLogSubmission, UpdateWorkingDirectory,
-                   ValidateChange, ValidateChangeLogAndReviewer, ValidateCommiterAndReviewer, WaitForCrashCollection,
+                   ValidateChange, ValidateChangeLogAndReviewer, ValidateCommitterAndReviewer, WaitForCrashCollection,
                    InstallBuiltProduct, VerifyGitHubIntegrity)
 
 
@@ -289,7 +289,7 @@
         factory.BuildFactory.__init__(self)
         self.addStep(ConfigureBuild(platform=platform, configuration=configuration, architectures=architectures, buildOnly=False, triggers=None, remotes=None, additionalArguments=additionalArguments))
         self.addStep(ValidateChange(verifycqplus=True))
-        self.addStep(ValidateCommiterAndReviewer())
+        self.addStep(ValidateCommitterAndReviewer())
         self.addStep(PrintConfiguration())
         self.addStep(CleanGitRepo(default_branch='master'))
         self.addStep(CheckOutSource(repourl='https://git.webkit.org/git/WebKit-https'))
@@ -321,3 +321,12 @@
         factory.BuildFactory.__init__(self)
         self.addStep(ConfigureBuild(platform=platform, configuration=configuration, architectures=architectures, buildOnly=False, triggers=None, remotes=None, additionalArguments=additionalArguments))
         self.addStep(ValidateChange(verifyMergeQueue=True, verifyNoDraftForMergeQueue=True))
+        self.addStep(ValidateCommitterAndReviewer())
+        self.addStep(PrintConfiguration())
+        self.addStep(CleanGitRepo())
+        self.addStep(CheckOutSource())
+        self.addStep(FetchBranches())
+        self.addStep(ShowIdentifier())
+        self.addStep(VerifyGitHubIntegrity())
+        self.addStep(UpdateWorkingDirectory())
+        self.addStep(CheckOutPullRequest())

Modified: trunk/Tools/CISupport/ews-build/factories_unittest.py (291618 => 291619)


--- trunk/Tools/CISupport/ews-build/factories_unittest.py	2022-03-22 15:24:09 UTC (rev 291618)
+++ trunk/Tools/CISupport/ews-build/factories_unittest.py	2022-03-22 15:25:30 UTC (rev 291619)
@@ -629,6 +629,15 @@
         'Merge-Queue': [
             'configure-build',
             'validate-change',
+            'validate-commiter-and-reviewer',
+            'configuration',
+            'clean-up-git-repo',
+            'clean-and-update-working-directory',
+            'fetch-branch-references',
+            'show-identifier',
+            'verify-github-integrity',
+            'update-working-directory',
+            'checkout-pull-request'
         ],
     }
 

Modified: trunk/Tools/CISupport/ews-build/steps.py (291618 => 291619)


--- trunk/Tools/CISupport/ews-build/steps.py	2022-03-22 15:24:09 UTC (rev 291618)
+++ trunk/Tools/CISupport/ews-build/steps.py	2022-03-22 15:25:30 UTC (rev 291619)
@@ -183,12 +183,29 @@
             self._addToLog('stdio', 'Unable to fetch pull request {}.\n'.format(pr_number))
             if attempt > retry:
                 return None
-            wait_for = (index + 1) * 15
+            wait_for = (attempt + 1) * 15
             self._addToLog('stdio', 'Backing off for {} seconds before retrying.\n'.format(wait_for))
             time.sleep(wait_for)
 
         return None
 
+    def get_reviewers(self, pr_number, repository_url=None):
+        api_url = GitHub.api_url(repository_url)
+        if not api_url:
+            return []
+
+        reviews_url = f'{api_url}/pulls/{pr_number}/reviews'
+        content = self.fetch_data_from_url_with_authentication(reviews_url)
+        if not content:
+            return []
+
+        result = []
+        for review in (content.json() or []):
+            reviewer = review.get('user', {}).get('login')
+            if reviewer and review.get('state') == 'APPROVED':
+                result.append(reviewer)
+        return result
+
     def _is_pr_closed(self, pr_json):
         if not pr_json or not pr_json.get('state'):
             self._addToLog('stdio', 'Cannot determine pull request status.\n')
@@ -1445,12 +1462,12 @@
         return True
 
 
-class ValidateCommiterAndReviewer(buildstep.BuildStep):
+class ValidateCommitterAndReviewer(buildstep.BuildStep, GitHubMixin):
     name = 'validate-commiter-and-reviewer'
     descriptionDone = ['Validated commiter and reviewer']
 
     def __init__(self, *args, **kwargs):
-        super(ValidateCommiterAndReviewer, self).__init__(*args, **kwargs)
+        super(ValidateCommitterAndReviewer, self).__init__(*args, **kwargs)
         self.contributors = {}
 
     @defer.inlineCallbacks
@@ -1466,15 +1483,21 @@
             return {'step': self.descriptionDone}
         return buildstep.BuildStep.getResultSummary(self)
 
-    def fail_build(self, email, status):
-        reason = '{} does not have {} permissions'.format(email, status)
-        comment = '{} does not have {} permissions according to {}.'.format(email, status, Contributors.url)
-        comment += '\n\nRejecting attachment {} from commit queue.'.format(self.getProperty('patch_id', ''))
+    def fail_build(self, email_or_username, status):
+        patch_id = self.getProperty('patch_id', '')
+        pr_number = self.getProperty('github.number', '')
+
+        reason = f'{email_or_username} does not have {status} permissions'
+        comment = f'{"@" if pr_number else ""}{email_or_username} does not have {status} permissions according to {Contributors.url}.'
+        if patch_id:
+            comment += f'\n\nRejecting attachment {patch_id} from commit queue.'
+        elif pr_number:
+            comment += f'\n\nRejecting {self.getProperty("github.head.sha", f"#{pr_number}")} from merge queue.'
         self.setProperty('comment_text', comment)
 
         self._addToLog('stdio', reason)
         self.setProperty('build_finish_summary', reason)
-        self.build.addStepsAfterCurrentStep([LeaveComment(), SetCommitQueueMinusFlagOnPatch()])
+        self.build.addStepsAfterCurrentStep([LeaveComment(), BlockPullRequest(), SetCommitQueueMinusFlagOnPatch()])
         self.finished(FAILURE)
         self.descriptionDone = reason
 
@@ -1503,24 +1526,40 @@
             self.descriptionDone = 'Failed to get contributors information'
             self.build.buildFinished(['Failed to get contributors information'], FAILURE)
             return None
-        patch_committer = self.getProperty('patch_committer', '').lower()
-        if not self.is_committer(patch_committer):
-            self.fail_build(patch_committer, 'committer')
+
+        pr_number = self.getProperty('github.number', '')
+
+        if pr_number:
+            committer = (self.getProperty('owners', []) or [''])[0]
+        else:
+            committer = self.getProperty('patch_committer', '').lower()
+
+        if not self.is_committer(committer):
+            self.fail_build(committer, 'committer')
             return None
-        self._addToLog('stdio', '{} is a valid commiter.\n'.format(patch_committer))
+        self._addToLog('stdio', f'{committer} is a valid commiter.\n')
 
-        reviewer = self.getProperty('reviewer', '').lower()
-        if not reviewer:
-            # Patch does not have r+ flag. This is acceptable, since the ChangeLog might have 'Reviewed by' in it.
+        if pr_number:
+            reviewers = self.get_reviewers(pr_number, self.getProperty('repository', ''))
+            if any([self.is_reviewer(reviewer) for reviewer in reviewers]):
+                reviewers = list(filter(self.is_reviewer, reviewers))
+        else:
+            reviewer = self.getProperty('reviewer', '').lower()
+            reviewers = [reviewer] if reviewer else []
+
+        if not reviewers:
+            # Change has not been reviewed in bug tracker. This is acceptable, since the ChangeLog might have 'Reviewed by' in it.
             self.descriptionDone = 'Validated committer'
             self.finished(SUCCESS)
             return None
 
-        self.setProperty('reviewers_full_names', [self.full_name_from_email(reviewer)])
-        if not self.is_reviewer(reviewer):
-            self.fail_build(reviewer, 'reviewer')
-            return None
-        self._addToLog('stdio', '{} is a valid reviewer.\n'.format(reviewer))
+        for reviewer in reviewers:
+            if not self.is_reviewer(reviewer):
+                self.fail_build(reviewer, 'reviewer')
+                return None
+            self._addToLog('stdio', f'{reviewer} is a valid reviewer.\n')
+        self.setProperty('reviewers_full_names', [self.full_name_from_email(reviewer) for reviewer in reviewers])
+
         self.finished(SUCCESS)
         return None
 

Modified: trunk/Tools/CISupport/ews-build/steps_unittest.py (291618 => 291619)


--- trunk/Tools/CISupport/ews-build/steps_unittest.py	2022-03-22 15:24:09 UTC (rev 291618)
+++ trunk/Tools/CISupport/ews-build/steps_unittest.py	2022-03-22 15:25:30 UTC (rev 291619)
@@ -56,7 +56,7 @@
                    RunWebKitTestsWithoutChange, RunWebKitTestsRedTree, RunWebKitTestsRepeatFailuresRedTree, RunWebKitTestsRepeatFailuresWithoutChangeRedTree,
                    RunWebKitTestsWithoutChangeRedTree, AnalyzeLayoutTestsResultsRedTree, TestWithFailureCount, ShowIdentifier,
                    Trigger, TransferToS3, UnApplyPatch, UpdateWorkingDirectory, UploadBuiltProduct,
-                   UploadTestResults, ValidateChangeLogAndReviewer, ValidateCommiterAndReviewer, ValidateChange, VerifyGitHubIntegrity)
+                   UploadTestResults, ValidateChangeLogAndReviewer, ValidateCommitterAndReviewer, ValidateChange, VerifyGitHubIntegrity)
 
 # Workaround for https://github.com/buildbot/buildbot/issues/4669
 from buildbot.test.fake.fakebuild import FakeBuild
@@ -5157,13 +5157,18 @@
         return rc
 
 
-class TestValidateCommiterAndReviewer(BuildStepMixinAdditions, unittest.TestCase):
+class TestValidateCommitterAndReviewer(BuildStepMixinAdditions, unittest.TestCase):
     def setUp(self):
         self.longMessage = True
 
         def mock_load_contributors(*args, **kwargs):
-            return {'aakash_j...@apple.com': {'name': 'Aakash Jain', 'status': 'reviewer'},
-                    'commit...@webkit.org': {'name': 'WebKit Committer', 'status': 'committer'}}, []
+            return {
+                'aakash_j...@apple.com': {'name': 'Aakash Jain', 'status': 'reviewer'},
+                'jain-aakash': {'name': 'Aakash Jain', 'status': 'reviewer'},
+                'commit...@webkit.org': {'name': 'WebKit Committer', 'status': 'committer'},
+                'webkit-commit-queue': {'name': 'WebKit Committer', 'status': 'committer'},
+            }, []
+
         Contributors.load = mock_load_contributors
         return self.setUpBuildStep()
 
@@ -5170,18 +5175,28 @@
     def tearDown(self):
         return self.tearDownBuildStep()
 
-    def test_success(self):
-        self.setupStep(ValidateCommiterAndReviewer())
+    def test_success_patch(self):
+        self.setupStep(ValidateCommitterAndReviewer())
         self.setProperty('patch_id', '1234')
         self.setProperty('patch_committer', 'commit...@webkit.org')
         self.setProperty('reviewer', 'aakash_j...@apple.com')
         self.expectHidden(False)
-        self.assertEqual(ValidateCommiterAndReviewer.haltOnFailure, False)
+        self.assertEqual(ValidateCommitterAndReviewer.haltOnFailure, False)
         self.expectOutcome(result=SUCCESS, state_string='Validated commiter and reviewer')
         return self.runStep()
 
-    def test_success_no_reviewer(self):
-        self.setupStep(ValidateCommiterAndReviewer())
+    def test_success_pr(self):
+        self.setupStep(ValidateCommitterAndReviewer())
+        ValidateCommitterAndReviewer.get_reviewers = lambda x, pull_request, repository_url=None: ['jain-aakash']
+        self.setProperty('github.number', '1234')
+        self.setProperty('owners', ['webkit-commit-queue'])
+        self.expectHidden(False)
+        self.assertEqual(ValidateCommitterAndReviewer.haltOnFailure, False)
+        self.expectOutcome(result=SUCCESS, state_string='Validated commiter and reviewer')
+        return self.runStep()
+
+    def test_success_no_reviewer_patch(self):
+        self.setupStep(ValidateCommitterAndReviewer())
         self.setProperty('patch_id', '1234')
         self.setProperty('patch_committer', 'aakash_j...@apple.com')
         self.expectHidden(False)
@@ -5188,8 +5203,17 @@
         self.expectOutcome(result=SUCCESS, state_string='Validated committer')
         return self.runStep()
 
-    def test_failure_load_contributors(self):
-        self.setupStep(ValidateCommiterAndReviewer())
+    def test_success_no_reviewer_pr(self):
+        self.setupStep(ValidateCommitterAndReviewer())
+        ValidateCommitterAndReviewer.get_reviewers = lambda x, pull_request, repository_url=None: []
+        self.setProperty('github.number', '1234')
+        self.setProperty('owners', ['jain-aakash'])
+        self.expectHidden(False)
+        self.expectOutcome(result=SUCCESS, state_string='Validated committer')
+        return self.runStep()
+
+    def test_failure_load_contributors_patch(self):
+        self.setupStep(ValidateCommitterAndReviewer())
         self.setProperty('patch_id', '1234')
         self.setProperty('patch_committer', 'a...@webkit.org')
         Contributors.load = lambda: ({}, [])
@@ -5197,8 +5221,17 @@
         self.expectOutcome(result=FAILURE, state_string='Failed to get contributors information')
         return self.runStep()
 
-    def test_failure_invalid_committer(self):
-        self.setupStep(ValidateCommiterAndReviewer())
+    def test_failure_load_contributors_pr(self):
+        self.setupStep(ValidateCommitterAndReviewer())
+        self.setProperty('github.number', '1234')
+        self.setProperty('owners', ['abc'])
+        Contributors.load = lambda: ({}, [])
+        self.expectHidden(False)
+        self.expectOutcome(result=FAILURE, state_string='Failed to get contributors information')
+        return self.runStep()
+
+    def test_failure_invalid_committer_patch(self):
+        self.setupStep(ValidateCommitterAndReviewer())
         self.setProperty('patch_id', '1234')
         self.setProperty('patch_committer', 'a...@webkit.org')
         self.expectHidden(False)
@@ -5205,8 +5238,16 @@
         self.expectOutcome(result=FAILURE, state_string='a...@webkit.org does not have committer permissions')
         return self.runStep()
 
-    def test_failure_invalid_reviewer(self):
-        self.setupStep(ValidateCommiterAndReviewer())
+    def test_failure_invalid_committer_pr(self):
+        self.setupStep(ValidateCommitterAndReviewer())
+        self.setProperty('github.number', '1234')
+        self.setProperty('owners', ['abc'])
+        self.expectHidden(False)
+        self.expectOutcome(result=FAILURE, state_string='abc does not have committer permissions')
+        return self.runStep()
+
+    def test_failure_invalid_reviewer_patch(self):
+        self.setupStep(ValidateCommitterAndReviewer())
         self.setProperty('patch_id', '1234')
         self.setProperty('patch_committer', 'aakash_j...@apple.com')
         self.setProperty('reviewer', 'commit...@webkit.org')
@@ -5214,6 +5255,15 @@
         self.expectOutcome(result=FAILURE, state_string='commit...@webkit.org does not have reviewer permissions')
         return self.runStep()
 
+    def test_failure_invalid_reviewer_pr(self):
+        self.setupStep(ValidateCommitterAndReviewer())
+        ValidateCommitterAndReviewer.get_reviewers = lambda x, pull_request, repository_url=None: ['webkit-commit-queue']
+        self.setProperty('github.number', '1234')
+        self.setProperty('owners', ['jain-aakash'])
+        self.expectHidden(False)
+        self.expectOutcome(result=FAILURE, state_string='webkit-commit-queue does not have reviewer permissions')
+        return self.runStep()
+
     def test_load_contributors_from_disk(self):
         contributors = filter(lambda element: element.get('name') == 'Aakash Jain', Contributors().load_from_disk()[0])
         self.assertEqual(list(contributors)[0]['emails'][0], 'aakash_j...@apple.com')

Modified: trunk/Tools/ChangeLog (291618 => 291619)


--- trunk/Tools/ChangeLog	2022-03-22 15:24:09 UTC (rev 291618)
+++ trunk/Tools/ChangeLog	2022-03-22 15:25:30 UTC (rev 291619)
@@ -1,3 +1,29 @@
+2022-03-21  Jonathan Bedard  <jbed...@apple.com>
+
+        [Merge-Queue] Add ValidateCommitterAndReviewer
+        https://bugs.webkit.org/show_bug.cgi?id=238150
+        <rdar://problem/90587620>
+
+        Reviewed by Aakash Jain.
+
+        * CISupport/ews-build/factories.py:
+        (CommitQueueFactory.__init__): Rename ValidateCommiterAndReviewer to ValidateCommiterAndReviewer.
+        (MergeQueueFactory.__init__): Add ValidateCommitterAndReviewer, PrintConfiguration, CleanGitRepo,
+        CheckOutSource, FetchBranches, ShowIdentifier, VerifyGitHubIntegrity, UpdateWorkingDirectory
+        and CheckOutPullRequest.
+        * CISupport/ews-build/factories_unittest.py:
+        (TestExpectedBuildSteps): Add Merge-Queue step names.
+        * CISupport/ews-build/steps.py:
+        (GitHubMixin.get_pr_json): Retry tied to attempt not index.
+        (GitHubMixin.get_reviewers): Get list of reviewers for pull-request in repository.
+        (ValidateCommitterAndReviewer): Renamed from ValidateCommiterAndReviewer, inherit from GitHubMixin.
+        (ValidateCommitterAndReviewer.__init__): Rename ValidateCommiterAndReviewer.
+        (ValidateCommitterAndReviewer.fail_build): Block pull request, differentiate comment for pull
+        request and patch.
+        (ValidateCommitterAndReviewer.start): Support pull requests.
+        (ValidateCommiterAndReviewer): Renamed to ValidateCommitterAndReviewer.
+        * CISupport/ews-build/steps_unittest.py:
+
 2022-03-22  Wenson Hsieh  <wenson_hs...@apple.com>
 
         -[WKWebView _spellCheckerDocumentTag] is inconsistent with the document tag passed into NSSpellChecker
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to