|
| 1 | +# This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | +# License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | +# file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 4 | +""" |
| 5 | +Functions for interacting with hg.mozilla.org APIs. |
| 6 | +""" |
| 7 | +import logging |
| 8 | +from typing import List |
| 9 | + |
| 10 | +from committelemetry.http import requests_retry_session |
| 11 | +from committelemetry.sentry import client as sentry |
| 12 | + |
| 13 | +log = logging.getLogger(__name__) |
| 14 | + |
| 15 | + |
| 16 | +def changesets_for_pushid(pushid: int, push_json_url: str) -> List[str]: |
| 17 | + """Return a list of changeset IDs in a repository push. |
| 18 | +
|
| 19 | + Reads data published by the Mozilla hgweb pushlog extension. |
| 20 | +
|
| 21 | + Also see https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/pushlog.html#writing-agents-that-consume-pushlog-data |
| 22 | +
|
| 23 | + Args: |
| 24 | + pushid: The integer pushlog pushid we want information about. |
| 25 | + push_json_url: The 'push_json_url' field from a hgpush message. |
| 26 | + See https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/notifications.html#changegroup-1 |
| 27 | + The pushid in the URL should match the pushid argument to this |
| 28 | + function. |
| 29 | +
|
| 30 | + Returns: |
| 31 | + A list of changeset ID strings (40 char hex strings). |
| 32 | + """ |
| 33 | + log.info(f'processing pushid {pushid}') |
| 34 | + sentry.extra_context({'pushid': pushid}) |
| 35 | + response = requests_retry_session().get(push_json_url) |
| 36 | + response.raise_for_status() |
| 37 | + |
| 38 | + # See https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmo/pushlog.html#version-2 |
| 39 | + changesets = response.json()['pushes'][str(pushid)]['changesets'] |
| 40 | + log.info(f'got {len(changesets)} changesets for pushid {pushid}') |
| 41 | + return changesets |
| 42 | + |
| 43 | + |
| 44 | +def fetch_changeset(changeset_id, repo_url): |
| 45 | + # Example URL: https://hg.mozilla.org/mozilla-central/json-rev/deafa2891c61 |
| 46 | + response = requests_retry_session( |
| 47 | + ).get(f'{repo_url}/json-rev/{changesetid}') |
| 48 | + if response.status_code == 404: |
| 49 | + raise NoSuchChangeset( |
| 50 | + f'The changeset {changesetid} does not exist in repository {repo_url}' # yapf:disable |
| 51 | + ) |
| 52 | + response.raise_for_status() |
| 53 | + return response.json() |
| 54 | + |
| 55 | + |
| 56 | +def utc_hgwebdate(hgweb_datejson): |
| 57 | + """Turn a (unixtime, offset) tuple back into a UTC Unix timestamp. |
| 58 | +
|
| 59 | + Pushlog entries are not in UTC, but a tuple of (local-unixtime, utc-offset) |
| 60 | + created by |
| 61 | + https://www.mercurial-scm.org/repo/hg/file/8b86acc7aa64/mercurial/utils/dateutil.py#l63. |
| 62 | + This function reverses the operation that created the tuple. |
| 63 | +
|
| 64 | + Args: |
| 65 | + hgweb_datejson: A 2-element JSON list of ints. |
| 66 | + For example: https://hg.mozilla.org/mozilla-central/json-rev/deafa2891c61 |
| 67 | + See https://www.mercurial-scm.org/repo/hg/file/8b86acc7aa64/mercurial/utils/dateutil.py#l63 |
| 68 | + for how this value is created. |
| 69 | +
|
| 70 | + Returns: |
| 71 | + The UTC Unix time (seconds since the epoch), as an int. |
| 72 | + """ |
| 73 | + assert len(hgweb_datejson) == 2 |
| 74 | + timestamp, offset = hgweb_datejson |
| 75 | + return timestamp + offset |
| 76 | + |
| 77 | + |
| 78 | +class Error(Exception): |
| 79 | + """Generic error class for this module.""" |
| 80 | + |
| 81 | + |
| 82 | +class NoSuchChangeset(Error): |
| 83 | + """Raised if the given changeset ID does not exist in the target system.""" |
0 commit comments