From 04b1956ce4bf48bc3fb6c3b7ec5f94cc5c9aa8c3 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Mon, 7 Oct 2019 20:01:20 -0400 Subject: [PATCH] DO NOT MERGE: Experiment with cron --- .github/workflows/pull_request.yml | 19 ++++ tools/ci/update_pr_preview.py | 172 +++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 .github/workflows/pull_request.yml create mode 100644 tools/ci/update_pr_preview.py diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000000..403d8bb345 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,19 @@ +on: + schedule: + - cron: '* * * * *' +name: Synchronize the Pull Request Preview +jobs: + update-pr-preview: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + with: + ref: refs/heads/master + fetch-depth: 50 + - name: update-pr-preview + uses: ./tools/docker/github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + entrypoint: python + args: tools/ci/update_pr_preview.py https://api.github.com diff --git a/tools/ci/update_pr_preview.py b/tools/ci/update_pr_preview.py new file mode 100644 index 0000000000..71ace31805 --- /dev/null +++ b/tools/ci/update_pr_preview.py @@ -0,0 +1,172 @@ +import json +import logging +import os +import random +import sys + +import requests + +active_label = 'pull-request-has-preview' + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class Status(object): + SUCCESS = 0 + FAIL = 1 + NEUTRAL = 0 + + +def request(url, method_name, data=None, json_data=None, ignore_body=False): + github_token = os.environ.get('GITHUB_TOKEN') + + kwargs = { + 'headers': { + 'Authorization': 'token {}'.format(github_token), + 'Accept': 'application/vnd.github.machine-man-preview+json' + } + } + method = getattr(requests, method_name) + + logger.info('Issuing request: {} {}'.format(method_name.upper(), url)) + if json_data is not None or data is not None: + kwargs['json'] = json_data + kwargs['data'] = data + + resp = method(url, **kwargs) + + resp.raise_for_status() + + if not ignore_body: + return resp.json() + + +def resource_exists(url): + try: + request(url, 'get', ignore_body=True) + except requests.HTTPError as exception: + if exception.response.status_code == 404: + return False + raise + + return True + + +class GitHub(object): + def __init__(self, api_root, owner, repo): + self.api_root = api_root + self.owner = owner + self.repo = repo + + def is_collaborator(self, login): + return resource_exists( + '{}/repos/{}/{}/collaborators/{}'.format( + self.api_root, self.owner, self.repo, login + ) + ) + + def ref_exists(self, ref): + return resource_exists( + '{}/repos/{}/{}/git/refs/{}'.format( + self.api_root, self.owner, self.repo, ref + ) + ) + + def create_ref(self, ref, sha): + data = { + 'ref': 'refs/{}'.format(ref), + 'sha': sha + } + url = '{}/repos/{}/{}/git/refs'.format( + self.api_root, self.owner, self.repo + ) + + logger.info('Creating ref "{}" as {}'.format(ref, sha)) + + request(url, 'post', json_data=data) + + def update_ref(self, ref, sha): + data = { + 'force': True, + 'sha': sha + } + url = '{}/repos/{}/{}/git/refs/{}'.format( + self.api_root, self.owner, self.repo, ref + ) + + logger.info('Updating ref "{}" as {}'.format(ref, sha)) + + request(url, 'patch', json_data=data) + + def delete_ref(self, ref): + url = '{}/repos/{}/{}/git/refs/{}'.format( + self.api_root, self.owner, self.repo, ref + ) + + logger.info('Deleting ref "{}"'.format(ref)) + + try: + request(url, 'delete', ignore_body=True) + except requests.HTTPError as exception: + if exception.response.status_code != 404: + raise + + logger.info( + 'Attempted to delete non-existent ref: {}'.format(ref) + ) + + def set_ref(self, ref, sha): + if self.ref_exists(ref): + self.update_ref(ref, sha) + else: + self.create_ref(ref, sha) + + def add_label(self, pr_number, label_name): + data = { + 'labels': [label_name] + } + url = '{}/repos/{}/{}/issues/{}/labels'.format( + self.api_root, self.owner, self.repo, pr_number + ) + + logger.info('Adding label') + + request(url, 'post', json_data=data) + + def remove_label(self, pr_number, label_name): + url = '{}/repos/{}/{}/issues/{}/labels/{}'.format( + self.api_root, self.owner, self.repo, pr_number, label_name + ) + + logger.info('Removing label') + + try: + request(url, 'delete') + except requests.HTTPError as exception: + if exception.response.status_code != 404: + raise + + logger.info( + 'Attempted to remove non-existent label: {}'.format(label_name) + ) + + +def main(api_root): + with open(os.environ['GITHUB_EVENT_PATH']) as handle: + event = json.load(handle) + logger.info(json.dumps(event, indent=2)) + + owner, repo = os.environ['GITHUB_REPOSITORY'].split('/', 1) + github = GitHub(api_root, owner, repo) + sha = '8be01b6e0d191a641f45ad59e83718155775921d' + name = 'heads/random-%d' % (random.random() * 1000) + github.set_ref(name, sha) + + return Status.SUCCESS + + +if __name__ == '__main__': + code = main(sys.argv[1]) + assert isinstance(code, int) + sys.exit(code)