File: hg.py

package info (click to toggle)
firefox 147.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,683,484 kB
  • sloc: cpp: 7,607,246; javascript: 6,533,185; ansic: 3,775,227; python: 1,415,393; xml: 634,561; asm: 438,951; java: 186,241; sh: 62,752; makefile: 18,079; objc: 13,092; perl: 12,808; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (129 lines) | stat: -rw-r--r-- 3,876 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


import logging
import subprocess

import requests
from mozbuild.util import memoize
from redo import retry

logger = logging.getLogger(__name__)

PUSHLOG_CHANGESET_TMPL = (
    "{repository}/json-pushes?version=2&changeset={revision}&tipsonly=1"
)
PUSHLOG_PUSHES_TMPL = (
    "{repository}/json-pushes/?version=2&startID={push_id_start}&endID={push_id_end}"
)


def _query_pushlog(url):
    response = retry(
        requests.get,
        attempts=5,
        sleeptime=10,
        args=(url,),
        kwargs={"timeout": 60, "headers": {"User-Agent": "TaskCluster"}},
    )

    return response.json()["pushes"]


def find_hg_revision_push_info(repository, revision):
    """Given the parameters for this action and a revision, find the
    pushlog_id of the revision."""
    url = PUSHLOG_CHANGESET_TMPL.format(repository=repository, revision=revision)

    pushes = _query_pushlog(url)

    if len(pushes) != 1:
        raise RuntimeError(
            f"Found {len(pushes)} pushlog_ids, expected 1, for {repository} revision {revision}: {pushes}"
        )

    pushid = list(pushes.keys())[0]
    return {
        "pushdate": pushes[pushid]["date"],
        "pushid": pushid,
        "user": pushes[pushid]["user"],
    }


@memoize
def get_push_data(repository, project, push_id_start, push_id_end):
    url = PUSHLOG_PUSHES_TMPL.format(
        repository=repository,
        push_id_start=push_id_start - 1,
        push_id_end=push_id_end,
    )

    try:
        pushes = _query_pushlog(url)

        return {
            push_id: pushes[str(push_id)]
            for push_id in range(push_id_start, push_id_end + 1)
        }

    # In the event of request times out, requests will raise a TimeoutError.
    except requests.exceptions.Timeout:
        logger.warning("json-pushes timeout")

    # In the event of a network problem (e.g. DNS failure, refused connection, etc),
    # requests will raise a ConnectionError.
    except requests.exceptions.ConnectionError:
        logger.warning("json-pushes connection error")

    # In the event of the rare invalid HTTP response(e.g 404, 401),
    # requests will raise an HTTPError exception
    except requests.exceptions.HTTPError:
        logger.warning("Bad Http response")

    # When we get invalid JSON (i.e. 500 error), it results in a ValueError (bug 1313426)
    except ValueError as error:
        logger.warning(f"Invalid JSON, possible server error: {error}")

    # We just print the error out as a debug message if we failed to catch the exception above
    except requests.exceptions.RequestException as error:
        logger.warning(error)

    return None


def get_hg_revision_branch(root, revision):
    """Given the parameters for a revision, find the hg_branch (aka
    relbranch) of the revision."""
    return get_hg_revision_info(root, revision, "branch")


def get_hg_revision_info(root, revision, info):
    return subprocess.check_output(
        [
            "hg",
            "identify",
            "-T",
            f"{{{info}}}",
            "--rev",
            revision,
        ],
        cwd=root,
        universal_newlines=True,
    )


# For these functions, we assume that run-task has correctly checked out the
# revision indicated by GECKO_HEAD_REF, so all that remains is to see what the
# current revision is.  Mercurial refers to that as `.`.
def get_hg_commit_message(root, rev="."):
    return subprocess.check_output(
        ["hg", "log", "-r", rev, "-T", "{desc}"], cwd=root, universal_newlines=True
    )


def calculate_head_rev(root):
    return subprocess.check_output(
        ["hg", "log", "-r", ".", "-T", "{node}"], cwd=root, universal_newlines=True
    )