示例#1
0
def test_build_stack_graph_disconnected_revisions_not_included(phabdouble):
    phab = phabdouble.get_phabricator_client()

    revisions = _build_revision_graph(
        phabdouble,
        [
            # Graph A.
            [],
            [0],
            [1],

            # Graph B.
            [],
            [3]
        ])

    # Graph A.
    nodes, edges = build_stack_graph(phab, revisions[0]['phid'])
    assert nodes == {r['phid'] for r in revisions[:3]}
    assert edges == {
        (revisions[1]['phid'], revisions[0]['phid']),
        (revisions[2]['phid'], revisions[1]['phid']),
    }

    # Graph B.
    nodes, edges = build_stack_graph(phab, revisions[3]['phid'])
    assert nodes == {r['phid'] for r in revisions[3:]}
    assert edges == {
        (revisions[4]['phid'], revisions[3]['phid']),
    }
示例#2
0
def test_build_stack_graph_multi_root_multi_head_multi_path(phabdouble):
    phab = phabdouble.get_phabricator_client()

    # Revision stack to construct:
    # *     revisions[10]
    # | *   revisions[9]
    # |/
    # *     revisions[8]
    # |\
    # | *   revisions[7]
    # * |   revisions[6]
    # * |   revisions[5]
    # | *   revisions[4]
    # |/
    # *     revisions[3]
    # |\
    # | *   revisions[2]
    # | *   revisions[1]
    # *     revisions[0]

    # fmt: off
    revisions = _build_revision_graph(
        phabdouble, [
            [],
            [],
            [1],
            [0, 2],
            [3],
            [3],
            [5],
            [4],
            [6, 7],
            [8],
            [8],
        ]
    )
    # fmt: on

    nodes, edges = build_stack_graph(phab, revisions[0]["phid"])
    assert nodes == {r["phid"] for r in revisions}
    assert edges == {
        (revisions[2]["phid"], revisions[1]["phid"]),
        (revisions[3]["phid"], revisions[2]["phid"]),
        (revisions[3]["phid"], revisions[0]["phid"]),
        (revisions[4]["phid"], revisions[3]["phid"]),
        (revisions[5]["phid"], revisions[3]["phid"]),
        (revisions[6]["phid"], revisions[5]["phid"]),
        (revisions[7]["phid"], revisions[4]["phid"]),
        (revisions[8]["phid"], revisions[6]["phid"]),
        (revisions[8]["phid"], revisions[7]["phid"]),
        (revisions[9]["phid"], revisions[8]["phid"]),
        (revisions[10]["phid"], revisions[8]["phid"]),
    }

    for r in revisions[1:]:
        nodes2, edges2 = build_stack_graph(phab, r["phid"])
        assert nodes2 == nodes
        assert edges2 == edges
示例#3
0
def test_build_stack_graph_two_nodes(phabdouble):
    phab = phabdouble.get_phabricator_client()
    r1 = phabdouble.revision()
    r2 = phabdouble.revision(depends_on=[r1])

    nodes, edges = build_stack_graph(phab, r1['phid'])
    assert nodes == {r1['phid'], r2['phid']}
    assert len(edges) == 1
    assert edges == {(r2['phid'], r1['phid'])}

    # Building from either revision should result in same graph.
    nodes2, edges2 = build_stack_graph(phab, r2['phid'])
    assert nodes2 == nodes
    assert edges2 == edges
示例#4
0
def test_calculate_landable_subgraphs_allows_distinct_repo_paths(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo1 = phabdouble.repo(name='repo1')
    r1 = phabdouble.revision(repo=repo1)
    r2 = phabdouble.revision(repo=repo1, depends_on=[r1])

    repo2 = phabdouble.repo(name='repo2')
    r3 = phabdouble.revision(repo=repo2)
    r4 = phabdouble.revision(repo=repo2, depends_on=[r3])

    r5 = phabdouble.revision(repo=repo1, depends_on=[r2, r4])

    nodes, edges = build_stack_graph(phab, r1['phid'])
    ext_data = request_extended_revision_data(phab, [
        r1['phid'],
        r2['phid'],
        r3['phid'],
        r4['phid'],
        r5['phid'],
    ])

    landable, _ = calculate_landable_subgraphs(ext_data, edges,
                                               {repo1['phid'], repo2['phid']})
    assert len(landable) == 2
    assert [r1['phid'], r2['phid']] in landable
    assert [r3['phid'], r4['phid']] in landable
示例#5
0
def test_calculate_landable_subgraphs_diverging_paths_merge(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo = phabdouble.repo()
    r1 = phabdouble.revision(repo=repo)

    r2 = phabdouble.revision(repo=repo, depends_on=[r1])
    r3 = phabdouble.revision(repo=repo, depends_on=[r2])

    r4 = phabdouble.revision(repo=repo, depends_on=[r1])
    r5 = phabdouble.revision(repo=repo, depends_on=[r4])

    r6 = phabdouble.revision(repo=repo, depends_on=[r1])

    r7 = phabdouble.revision(repo=repo, depends_on=[r3, r5, r6])

    nodes, edges = build_stack_graph(phab, r1['phid'])
    ext_data = request_extended_revision_data(phab, [
        r1['phid'],
        r2['phid'],
        r3['phid'],
        r4['phid'],
        r5['phid'],
        r6['phid'],
        r7['phid'],
    ])

    landable, _ = calculate_landable_subgraphs(ext_data, edges, {repo['phid']})
    assert len(landable) == 3
    assert [r1['phid'], r2['phid'], r3['phid']] in landable
    assert [r1['phid'], r4['phid'], r5['phid']] in landable
    assert [r1['phid'], r6['phid']] in landable
示例#6
0
def test_calculate_landable_subgraphs_extra_check(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo = phabdouble.repo()
    r1 = phabdouble.revision(repo=repo)
    r2 = phabdouble.revision(repo=repo, depends_on=[r1])
    r3 = phabdouble.revision(repo=repo, depends_on=[r2])
    r4 = phabdouble.revision(repo=repo, depends_on=[r3])

    nodes, edges = build_stack_graph(phab, r1['phid'])
    ext_data = request_extended_revision_data(
        phab, [r1['phid'], r2['phid'], r3['phid'], r4['phid']])

    REASON = "Blocked by custom check."

    def custom_check(*, revision, diff, repo):
        return REASON if revision['id'] == r3['id'] else None

    landable, blocked = calculate_landable_subgraphs(
        ext_data, edges, {repo['phid']}, other_checks=[custom_check])
    assert landable == [
        [r1['phid'], r2['phid']],
    ]
    assert r3['phid'] in blocked and r4['phid'] in blocked
    assert blocked[r3['phid']] == REASON
def get_list(stack_revision_id):
    """Return a list of Transplant objects"""
    revision_id = revision_id_to_int(stack_revision_id)

    phab = g.phabricator
    revision = phab.call_conduit("differential.revision.search",
                                 constraints={"ids": [revision_id]})
    revision = phab.single(revision, "data", none_when_empty=True)
    if revision is None:
        return problem(
            404,
            "Revision not found",
            "The revision does not exist or you lack permission to see it.",
            type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
        )

    # TODO: This assumes that all revisions and related objects in the stack
    # have uniform view permissions for the requesting user. Some revisions
    # being restricted could cause this to fail.
    nodes, edges = build_stack_graph(phab, phab.expect(revision, "phid"))
    revision_phids = list(nodes)
    revs = phab.call_conduit(
        "differential.revision.search",
        constraints={"phids": revision_phids},
        limit=len(revision_phids),
    )

    transplants = Transplant.revisions_query(
        [phab.expect(r, "id") for r in phab.expect(revs, "data")]).all()
    return [t.serialize() for t in transplants], 200
示例#8
0
def test_build_stack_graph_single_node(phabdouble):
    phab = phabdouble.get_phabricator_client()
    revision = phabdouble.revision()

    nodes, edges = build_stack_graph(phab, revision['phid'])
    assert len(nodes) == 1
    assert nodes.pop() == revision['phid']
    assert not edges
示例#9
0
def test_calculate_landable_subgraphs_closed_root(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo = phabdouble.repo()
    r1 = phabdouble.revision(repo=repo, status=RevisionStatus.PUBLISHED)
    r2 = phabdouble.revision(repo=repo, depends_on=[r1])

    nodes, edges = build_stack_graph(phab, r1["phid"])
    ext_data = request_extended_revision_data(phab, [r1["phid"], r2["phid"]])

    landable, _ = calculate_landable_subgraphs(ext_data, edges, {repo["phid"]})
    assert landable == [[r2["phid"]]]
示例#10
0
def test_calculate_landable_subgraphs_stops_multiple_repo_paths(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo1 = phabdouble.repo(name="repo1")
    repo2 = phabdouble.repo(name="repo2")
    r1 = phabdouble.revision(repo=repo1)
    r2 = phabdouble.revision(repo=repo1, depends_on=[r1])
    r3 = phabdouble.revision(repo=repo2, depends_on=[r2])

    nodes, edges = build_stack_graph(phab, r1["phid"])
    ext_data = request_extended_revision_data(
        phab, [r1["phid"], r2["phid"], r3["phid"]])

    landable, _ = calculate_landable_subgraphs(ext_data, edges,
                                               {repo1["phid"], repo2["phid"]})
    assert landable == [[r1["phid"], r2["phid"]]]
示例#11
0
def get_list(stack_revision_id):
    """Return a list of Transplant objects"""
    revision_id = revision_id_to_int(stack_revision_id)

    phab = g.phabricator
    revision = phab.call_conduit(
        "differential.revision.search", constraints={"ids": [revision_id]}
    )
    revision = phab.single(revision, "data", none_when_empty=True)
    if revision is None:
        return problem(
            404,
            "Revision not found",
            "The revision does not exist or you lack permission to see it.",
            type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
        )

    # TODO: This assumes that all revisions and related objects in the stack
    # have uniform view permissions for the requesting user. Some revisions
    # being restricted could cause this to fail.
    nodes, edges = build_stack_graph(phab, phab.expect(revision, "phid"))
    revision_phids = list(nodes)
    revs = phab.call_conduit(
        "differential.revision.search",
        constraints={"phids": revision_phids},
        limit=len(revision_phids),
    )

    # Return both transplants and landing jobs, since for repos that were switched
    # both or either of these could be populated.

    rev_ids = [phab.expect(r, "id") for r in phab.expect(revs, "data")]

    transplants = Transplant.revisions_query(rev_ids).all()
    landing_jobs = LandingJob.revisions_query(rev_ids).all()

    if transplants and landing_jobs:
        logger.warning(
            "Both {} transplants and {} landing jobs found for this revision".format(
                str(len(transplants)), str(len(landing_jobs))
            )
        )

    return (
        [t.serialize() for t in transplants] + [j.serialize() for j in landing_jobs],
        200,
    )
def _find_stack_from_landing_path(phab, landing_path):
    a_revision_id = _choose_middle_revision_from_path(landing_path)
    revision = phab.call_conduit("differential.revision.search",
                                 constraints={"ids": [a_revision_id]})
    revision = phab.single(revision, "data", none_when_empty=True)
    if revision is None:
        raise ProblemException(
            404,
            "Stack Not Found",
            "The stack does not exist or you lack permission to see it.",
            type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
        )

    # TODO: This assumes that all revisions and related objects in the stack
    # have uniform view permissions for the requesting user. Some revisions
    # being restricted could cause this to fail.
    return build_stack_graph(phab, phab.expect(revision, "phid"))
示例#13
0
def test_calculate_landable_subgraphs_different_repo_closed_parent(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo1 = phabdouble.repo(name="repo1")
    r1 = phabdouble.revision(repo=repo1, status=RevisionStatus.PUBLISHED)

    repo2 = phabdouble.repo(name="repo2")
    r2 = phabdouble.revision(repo=repo2)

    r3 = phabdouble.revision(repo=repo2, depends_on=[r1, r2])

    nodes, edges = build_stack_graph(phab, r1["phid"])
    ext_data = request_extended_revision_data(
        phab, [r1["phid"], r2["phid"], r3["phid"]])

    landable, _ = calculate_landable_subgraphs(ext_data, edges,
                                               {repo1["phid"], repo2["phid"]})
    assert len(landable) == 1
    assert [r2["phid"], r3["phid"]] in landable
示例#14
0
def test_calculate_landable_subgraphs_missing_repo(phabdouble):
    """Test to assert a missing repository for a revision is
    blocked with an appropriate error
    """
    phab = phabdouble.get_phabricator_client()
    repo1 = phabdouble.repo()
    r1 = phabdouble.revision(repo=None)

    nodes, edges = build_stack_graph(phab, r1["phid"])
    revision_data = request_extended_revision_data(phab, [r1["phid"]])

    landable, blocked = calculate_landable_subgraphs(revision_data, edges,
                                                     {repo1["phid"]})

    repo_unset_warning = ("Revision's repository unset. Specify a target using"
                          '"Edit revision" in Phabricator')

    assert not landable
    assert r1["phid"] in blocked
    assert blocked[r1["phid"]] == repo_unset_warning
示例#15
0
def test_calculate_landable_subgraphs_closed_root_child_merges(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repo = phabdouble.repo()
    r1 = phabdouble.revision(repo=repo)
    r2 = phabdouble.revision(repo=repo, depends_on=[r1])
    r3 = phabdouble.revision(repo=repo, status=RevisionStatus.PUBLISHED)
    r4 = phabdouble.revision(repo=repo, depends_on=[r2, r3])

    nodes, edges = build_stack_graph(phab, r1['phid'])
    ext_data = request_extended_revision_data(phab, [
        r1['phid'],
        r2['phid'],
        r3['phid'],
        r4['phid'],
    ])

    landable, _ = calculate_landable_subgraphs(ext_data, edges, {repo['phid']})
    assert [r3['phid']] not in landable
    assert [r3['phid'], r4['phid']] not in landable
    assert [r4['phid']] not in landable
    assert landable == [[r1['phid'], r2['phid'], r4['phid']]]
示例#16
0
def get(revision_id):
    """Get the stack a revision is part of.

    Args:
        revision_id: (string) ID of the revision in 'D{number}' format
    """
    revision_id = revision_id_to_int(revision_id)

    phab = g.phabricator
    revision = phab.call_conduit("differential.revision.search",
                                 constraints={"ids": [revision_id]})
    revision = phab.single(revision, "data", none_when_empty=True)
    if revision is None:
        return not_found_problem

    try:
        nodes, edges = build_stack_graph(phab, phab.expect(revision, "phid"))
    except PhabricatorAPIException:
        # If a revision within the stack causes an API exception, treat the whole stack
        # as not found.
        return not_found_problem
    stack_data = request_extended_revision_data(phab, [phid for phid in nodes])

    supported_repos = get_repos_for_env(current_app.config.get("ENVIRONMENT"))
    landable_repos = get_landable_repos_for_revision_data(
        stack_data, supported_repos)

    other_checks = get_blocker_checks(
        repositories=supported_repos,
        relman_group_phid=get_relman_group_phid(phab))

    landable, blocked = calculate_landable_subgraphs(stack_data,
                                                     edges,
                                                     landable_repos,
                                                     other_checks=other_checks)
    uplift_repos = [
        name for name, repo in supported_repos.items()
        if repo.approval_required
    ]

    involved_phids = set()
    for revision in stack_data.revisions.values():
        involved_phids.update(gather_involved_phids(revision))

    involved_phids = list(involved_phids)

    users = user_search(phab, involved_phids)
    projects = project_search(phab, involved_phids)

    secure_project_phid = get_secure_project_phid(phab)
    sec_approval_project_phid = get_sec_approval_project_phid(phab)

    revisions_response = []
    for _phid, revision in stack_data.revisions.items():
        revision_phid = PhabricatorClient.expect(revision, "phid")
        fields = PhabricatorClient.expect(revision, "fields")
        diff_phid = PhabricatorClient.expect(fields, "diffPHID")
        diff = stack_data.diffs[diff_phid]
        human_revision_id = "D{}".format(
            PhabricatorClient.expect(revision, "id"))
        revision_url = urllib.parse.urljoin(
            current_app.config["PHABRICATOR_URL"], human_revision_id)
        secure = revision_is_secure(revision, secure_project_phid)
        commit_description = find_title_and_summary_for_display(
            phab, revision, secure)
        bug_id = get_bugzilla_bug(revision)
        reviewers = get_collated_reviewers(revision)
        accepted_reviewers = reviewers_for_commit_message(
            reviewers, users, projects, sec_approval_project_phid)
        commit_message_title, commit_message = format_commit_message(
            commit_description.title,
            bug_id,
            accepted_reviewers,
            commit_description.summary,
            revision_url,
        )
        author_response = serialize_author(phab.expect(fields, "authorPHID"),
                                           users)

        revisions_response.append({
            "id":
            human_revision_id,
            "phid":
            revision_phid,
            "status":
            serialize_status(revision),
            "blocked_reason":
            blocked.get(revision_phid, ""),
            "bug_id":
            bug_id,
            "title":
            commit_description.title,
            "url":
            revision_url,
            "date_created":
            PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, "fields",
                                         "dateCreated")).isoformat(),
            "date_modified":
            PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, "fields",
                                         "dateModified")).isoformat(),
            "summary":
            commit_description.summary,
            "commit_message_title":
            commit_message_title,
            "commit_message":
            commit_message,
            "repo_phid":
            PhabricatorClient.expect(fields, "repositoryPHID"),
            "diff":
            serialize_diff(diff),
            "author":
            author_response,
            "reviewers":
            serialize_reviewers(reviewers, users, projects, diff_phid),
            "is_secure":
            secure,
            "is_using_secure_commit_message":
            commit_description.sanitized,
        })

    repositories = []
    for phid in stack_data.repositories.keys():
        short_name = PhabricatorClient.expect(stack_data.repositories[phid],
                                              "fields", "shortName")

        repo = supported_repos.get(short_name)
        landing_supported = repo is not None
        url = (repo.url if landing_supported else
               f"{current_app.config['PHABRICATOR_URL']}/source/{short_name}")

        repositories.append({
            "approval_required": landing_supported and repo.approval_required,
            "commit_flags": repo.commit_flags if repo else [],
            "landing_supported": landing_supported,
            "phid": phid,
            "short_name": short_name,
            "url": url,
        })

    return {
        "repositories": repositories,
        "revisions": revisions_response,
        "edges": [e for e in edges],
        "landable_paths": landable,
        "uplift_repositories": uplift_repos,
    }
示例#17
0
def test_calculate_landable_subgraphs_complex_graph(phabdouble):
    phab = phabdouble.get_phabricator_client()

    repoA = phabdouble.repo(name='repoA')
    repoB = phabdouble.repo(name='repoB')
    repoC = phabdouble.repo(name='repoC')

    # Revision stack to construct:
    # *         rB4
    # |\
    # | *       rB3
    # * |       rB2 (CLOSED)
    #   | *     rC1
    #   |/
    #   *       rA10
    #  /|\
    # * | |     rB1
    #   | *     rA9 (CLOSED)
    #   *       rA8
    #   | *     rA7
    #   |/
    #   *       rA6
    #  /|
    # | *       rA5
    # | *       rA4
    # * |\      rA3 (CLOSED)
    # | * |     rA2
    #  \|/
    #   *       rA1 (CLOSED)

    rA1 = phabdouble.revision(repo=repoA, status=RevisionStatus.PUBLISHED)
    rA2 = phabdouble.revision(repo=repoA, depends_on=[rA1])
    rA3 = phabdouble.revision(repo=repoA,
                              status=RevisionStatus.PUBLISHED,
                              depends_on=[rA1])
    rA4 = phabdouble.revision(repo=repoA, depends_on=[rA1, rA2])
    rA5 = phabdouble.revision(repo=repoA, depends_on=[rA4])
    rA6 = phabdouble.revision(repo=repoA, depends_on=[rA3, rA5])
    rA7 = phabdouble.revision(repo=repoA, depends_on=[rA6])
    rA8 = phabdouble.revision(repo=repoA, depends_on=[rA6])
    rA9 = phabdouble.revision(repo=repoA, status=RevisionStatus.PUBLISHED)

    rB1 = phabdouble.revision(repo=repoB)

    rA10 = phabdouble.revision(repo=repoA, depends_on=[rA8, rA9, rB1])

    rC1 = phabdouble.revision(repo=repoC, depends_on=[rA10])

    rB2 = phabdouble.revision(repo=repoB, status=RevisionStatus.PUBLISHED)
    rB3 = phabdouble.revision(repo=repoB, depends_on=[rA10])
    rB4 = phabdouble.revision(repo=repoB, depends_on=[rB2, rB3])

    nodes, edges = build_stack_graph(phab, rA1['phid'])
    ext_data = request_extended_revision_data(phab, [
        rA1['phid'],
        rA2['phid'],
        rA3['phid'],
        rA4['phid'],
        rA5['phid'],
        rA6['phid'],
        rA7['phid'],
        rA8['phid'],
        rA9['phid'],
        rA10['phid'],
        rB1['phid'],
        rB2['phid'],
        rB3['phid'],
        rB4['phid'],
        rC1['phid'],
    ])

    landable, _ = calculate_landable_subgraphs(ext_data, edges,
                                               {repoA['phid'], repoB['phid']})
    assert len(landable) == 3
    assert [
        rA2['phid'],
        rA4['phid'],
        rA5['phid'],
        rA6['phid'],
        rA7['phid'],
    ] in landable
    assert [
        rA2['phid'],
        rA4['phid'],
        rA5['phid'],
        rA6['phid'],
        rA8['phid'],
    ] in landable
    assert [rB1['phid']] in landable
示例#18
0
def get(revision_id):
    """Get the stack a revision is part of.

    Args:
        revision_id: (string) ID of the revision in 'D{number}' format
    """
    revision_id = revision_id_to_int(revision_id)

    phab = g.phabricator
    revision = phab.call_conduit("differential.revision.search",
                                 constraints={"ids": [revision_id]})
    revision = phab.single(revision, "data", none_when_empty=True)
    if revision is None:
        return problem(
            404,
            "Revision not found",
            "The requested revision does not exist",
            type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
        )

    # TODO: This assumes that all revisions and related objects in the stack
    # have uniform view permissions for the requesting user. Some revisions
    # being restricted could cause this to fail.
    nodes, edges = build_stack_graph(phab, phab.expect(revision, "phid"))
    stack_data = request_extended_revision_data(phab, [phid for phid in nodes])

    supported_repos = get_repos_for_env(current_app.config.get("ENVIRONMENT"))
    landable_repos = get_landable_repos_for_revision_data(
        stack_data, supported_repos)

    other_checks = get_blocker_checks(
        repositories=supported_repos,
        relman_group_phid=get_relman_group_phid(phab))

    landable, blocked = calculate_landable_subgraphs(stack_data,
                                                     edges,
                                                     landable_repos,
                                                     other_checks=other_checks)
    uplift_repos = [
        name for name, repo in supported_repos.items()
        if repo.approval_required
    ]

    involved_phids = set()
    for revision in stack_data.revisions.values():
        involved_phids.update(gather_involved_phids(revision))

    involved_phids = list(involved_phids)

    users = user_search(phab, involved_phids)
    projects = project_search(phab, involved_phids)

    secure_project_phid = get_secure_project_phid(phab)
    sec_approval_project_phid = get_sec_approval_project_phid(phab)

    revisions_response = []
    for _phid, revision in stack_data.revisions.items():
        revision_phid = PhabricatorClient.expect(revision, "phid")
        fields = PhabricatorClient.expect(revision, "fields")
        diff_phid = PhabricatorClient.expect(fields, "diffPHID")
        diff = stack_data.diffs[diff_phid]
        human_revision_id = "D{}".format(
            PhabricatorClient.expect(revision, "id"))
        revision_url = urllib.parse.urljoin(
            current_app.config["PHABRICATOR_URL"], human_revision_id)
        secure = revision_is_secure(revision, secure_project_phid)
        commit_description = find_title_and_summary_for_display(
            phab, revision, secure)
        bug_id = get_bugzilla_bug(revision)
        reviewers = get_collated_reviewers(revision)
        accepted_reviewers = reviewers_for_commit_message(
            reviewers, users, projects, sec_approval_project_phid)
        commit_message_title, commit_message = format_commit_message(
            commit_description.title,
            bug_id,
            accepted_reviewers,
            commit_description.summary,
            revision_url,
        )
        author_response = serialize_author(phab.expect(fields, "authorPHID"),
                                           users)

        revisions_response.append({
            "id":
            human_revision_id,
            "phid":
            revision_phid,
            "status":
            serialize_status(revision),
            "blocked_reason":
            blocked.get(revision_phid, ""),
            "bug_id":
            bug_id,
            "title":
            commit_description.title,
            "url":
            revision_url,
            "date_created":
            PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, "fields",
                                         "dateCreated")).isoformat(),
            "date_modified":
            PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, "fields",
                                         "dateModified")).isoformat(),
            "summary":
            commit_description.summary,
            "commit_message_title":
            commit_message_title,
            "commit_message":
            commit_message,
            "repo_phid":
            PhabricatorClient.expect(fields, "repositoryPHID"),
            "diff":
            serialize_diff(diff),
            "author":
            author_response,
            "reviewers":
            serialize_reviewers(reviewers, users, projects, diff_phid),
            "is_secure":
            secure,
            "is_using_secure_commit_message":
            commit_description.sanitized,
        })

    repositories = []
    for phid in stack_data.repositories.keys():
        short_name = PhabricatorClient.expect(stack_data.repositories[phid],
                                              "fields", "shortName")
        repo = supported_repos.get(short_name)
        if repo is None:
            landing_supported, approval_required = False, None
        else:
            landing_supported, approval_required = True, repo.approval_required
        url = ("{phabricator_url}/source/{short_name}".format(
            phabricator_url=current_app.config["PHABRICATOR_URL"],
            short_name=short_name,
        ) if not landing_supported else supported_repos[short_name].url)
        repositories.append({
            "phid": phid,
            "short_name": short_name,
            "url": url,
            "landing_supported": landing_supported,
            "approval_required": approval_required,
        })

    return {
        "repositories": repositories,
        "revisions": revisions_response,
        "edges": [e for e in edges],
        "landable_paths": landable,
        "uplift_repositories": uplift_repos,
    }
示例#19
0
def get(revision_id):
    """Get the stack a revision is part of.

    Args:
        revision_id: (string) ID of the revision in 'D{number}' format
    """
    revision_id = revision_id_to_int(revision_id)

    phab = g.phabricator
    revision = phab.call_conduit(
        'differential.revision.search',
        constraints={'ids': [revision_id]},
    )
    revision = phab.single(revision, 'data', none_when_empty=True)
    if revision is None:
        return problem(
            404,
            'Revision not found',
            'The requested revision does not exist',
            type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404'
        )

    # TODO: This assumes that all revisions and related objects in the stack
    # have uniform view permissions for the requesting user. Some revisions
    # being restricted could cause this to fail.
    nodes, edges = build_stack_graph(phab, phab.expect(revision, 'phid'))
    stack_data = request_extended_revision_data(phab, [phid for phid in nodes])

    supported_repos = get_repos_for_env(current_app.config.get('ENVIRONMENT'))
    landable_repos = get_landable_repos_for_revision_data(
        stack_data, supported_repos
    )
    landable, blocked = calculate_landable_subgraphs(
        stack_data,
        edges,
        landable_repos,
        other_checks=DEFAULT_OTHER_BLOCKER_CHECKS
    )

    involved_phids = set()
    for revision in stack_data.revisions.values():
        involved_phids.update(gather_involved_phids(revision))

    involved_phids = list(involved_phids)

    users = lazy_user_search(phab, involved_phids)()
    projects = lazy_project_search(phab, involved_phids)()

    revisions_response = []
    for phid, revision in stack_data.revisions.items():
        revision_phid = PhabricatorClient.expect(revision, 'phid')
        fields = PhabricatorClient.expect(revision, 'fields')
        diff_phid = PhabricatorClient.expect(fields, 'diffPHID')
        diff = stack_data.diffs[diff_phid]
        human_revision_id = 'D{}'.format(
            PhabricatorClient.expect(revision, 'id')
        )
        revision_url = urllib.parse.urljoin(
            current_app.config['PHABRICATOR_URL'], human_revision_id
        )
        title = PhabricatorClient.expect(fields, 'title')
        summary = PhabricatorClient.expect(fields, 'summary')
        bug_id = get_bugzilla_bug(revision)
        reviewers = get_collated_reviewers(revision)
        accepted_reviewers = [
            reviewer_identity(phid, users, projects).identifier
            for phid, r in reviewers.items()
            if r['status'] is ReviewerStatus.ACCEPTED
        ]
        commit_message_title, commit_message = format_commit_message(
            title, bug_id, accepted_reviewers, summary, revision_url
        )
        author_response = serialize_author(
            phab.expect(fields, 'authorPHID'), users
        )

        revisions_response.append({
            'id': human_revision_id,
            'phid': revision_phid,
            'status': serialize_status(revision),
            'blocked_reason': blocked.get(revision_phid, ''),
            'bug_id': bug_id,
            'title': title,
            'url': revision_url,
            'date_created': PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, 'fields', 'dateCreated')
            ).isoformat(),
            'date_modified': PhabricatorClient.to_datetime(
                PhabricatorClient.expect(revision, 'fields', 'dateModified')
            ).isoformat(),
            'summary': summary,
            'commit_message_title': commit_message_title,
            'commit_message': commit_message,
            'diff': serialize_diff(diff),
            'author': author_response,
            'reviewers': serialize_reviewers(
                reviewers, users, projects, diff_phid
            ),
        })  # yapf: disable

    return {
        'revisions': revisions_response,
        'edges': [e for e in edges],
        'landable_paths': landable,
    }