如何通过GitHub API获取仓库的分支数量?

3
我正在设计一个UI界面,用于列出给定用户或组织的所有代码库。这是使用树形格式,其中第一级是代码库,第二级层次结构(子节点)应该是每个分支,如果展开的话。
我正在使用一种机制,它有意不需要我拉取给定代码库的所有分支列表,因为API对API调用有速率限制。相反,我只需要指示它包含多少子节点,而不实际为它们分配值(直到用户展开它)。我几乎确定获取代码库列表包括结果中的分支计数,但令我失望的是,我没有看到它。我只能看到forks、stargazers、watchers、issues等的计数。除了分支计数之外,其他都有。
UI的意图是在用户展开父节点后异步加载实际分支来填充,但它事先会知道要填充子节点的数量,因此立即显示每个分支的空占位符。再次强调,由于需要避免过多的API调用,所以在用户滚动时,它将使用分页来仅获取所需显示给用户的页面,并将其缓存以供以后显示。具体而言,我正在使用Delphi的Virtual TreeView。
procedure TfrmMain.LstInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
  var ChildCount: Cardinal);
var
  L: Integer;
  R: TGitHubRepo;
begin
  L:= Lst.GetNodeLevel(Node);
  case L of
    0: begin
      //TODO: Return number of branches...
      R:= TGitHubRepo(Lst.GetNodeData(Node));
      ChildCount:= R.I['branch_count']; //TODO: There is no such thing!!!
    end;
    1: ChildCount:= 0; //Branches have no further child nodes
  end;
end;

有没有什么方法可以让我获取存储库分支计数而无需预先获取完整列表?


1
如果您在速率限制方面遇到问题,请考虑实施条件请求,这样重复查询就不会计入您的限制。 - Schwern
我从未考虑过的一件事是,每个代码库都至少有一个分支。因此,我总是可以显示[+]来展开任何代码库,只有在那时它才会关心获取任何内容。在那一点上,我可以使用分页加载所有分支,甚至可能一次性加载所有分支。展开一个的成本可能很高,但至少我不需要提前知道总数。我之所以需要首先知道这一点的原因是我想知道是否要在任何东西上放置[+]展开器。但由于所有代码库都有一个默认分支,它们都有一个。 - Jerry Dodge
1个回答

4
你可以使用新的 GraphQL API替代。这使您可以将查询和结果定制为您所需的内容。而不是先获取计数,然后再填充分支,您可以在一个查询中完成两者。
尝试使用 Query Explorer
query {
  repository(owner: "octocat", name: "Hello-World") {
    refs(first: 100, refPrefix:"refs/heads/") {
      totalCount
      nodes {
        name
      }
    },
    pullRequests(states:[OPEN]) {
        totalCount
    }
  }
}

{
  "data": {
    "repository": {
      "refs": {
        "totalCount": 3,
        "nodes": [
          {
            "name": "master"
          },
          {
            "name": "octocat-patch-1"
          },
          {
            "name": "test"
          }
        ]
      },
      "pullRequests": {
        "totalCount": 192
      }
    }
  }
}

分页是通过光标实现的。首先获取前100个页面,但出于简洁起见,我们只使用了2个。响应将包含一个唯一的光标。

{
  repository(owner: "octocat", name: "Hello-World") {
    pullRequests(first:2, states: [OPEN]) {
      edges {
        node {
          title
        }
        cursor
      }
    }
  }
}

{
  "data": {
    "repository": {
      "pullRequests": {
        "edges": [
          {
            "node": {
              "title": "Update README"
            },
            "cursor": "Y3Vyc29yOnYyOpHOABRYHg=="
          },
          {
            "node": {
              "title": "Just a pull request test"
            },
            "cursor": "Y3Vyc29yOnYyOpHOABR2bQ=="
          }
        ]
      }
    }
  }
}

您可以在游标之后请求更多元素。这将获取接下来的2个元素。
{
  repository(owner: "octocat", name: "Hello-World") {
    pullRequests(first:2, after: "Y3Vyc29yOnYyOpHOABR2bQ==", states: [OPEN]) {
      edges {
        node {
          title
        }
        cursor
      }
    }
  }
}

查询可以像函数一样编写并传递参数。这些参数以单独的JSON位发送。这使得查询成为一个简单的不变字符串。

这个查询与之前的相同。

query NextPullRequestPage($pullRequestCursor:String) {
  repository(owner: "octocat", name: "Hello-World") {
    pullRequests(first:2, after: $pullRequestCursor, states: [OPEN]) {
      edges {
        node {
          title
        }
        cursor
      }
    }
  }
}

{
  "pullRequestCursor": "Y3Vyc29yOnYyOpHOABR2bQ=="
}

{ "pullRequestCursor": null } 将获取第一页。


它的速率限制计算比REST API更复杂。您每小时获得5000个点,而不是每小时调用次数。每个查询都会消耗一定数量的点数,这大致对应于Github计算结果的成本。您可以通过请求其rateLimit信息来了解查询的成本。如果您传递dryRun: true,它将仅告诉您运行查询的成本。

{
  rateLimit(dryRun:true) {
    limit
    cost
    remaining
    resetAt
  }
  repository(owner: "octocat", name: "Hello-World") {
    refs(first: 100, refPrefix: "refs/heads/") {
      totalCount
      nodes {
        name
      }
    }
    pullRequests(states: [OPEN]) {
      totalCount
    }
  }
}

{
  "data": {
    "rateLimit": {
      "limit": 5000,
      "cost": 1,
      "remaining": 4979,
      "resetAt": "2019-08-21T05:13:56Z"
    }
  }
}

这个查询只需要一个点。我还剩下4979个点,我的速率限制将在05:13 UTC重置。
GraphQL API非常灵活。使用它可以更有效地利用Github资源,并减少编程以解决速率限制问题。

如果我能为那个关于速率限制的后来编辑再次点赞,我一定会这样做。不幸的是,今晚我已经喝了第六瓶啤酒,可能明天晚上才能继续。我以前见过并使用过GraphQL,但从未真正使用过,也从未从Delphi中使用过它。但似乎很容易融入到我正在做的事情中。特别是为了摆脱90%的repo URL无用垃圾。 - Jerry Dodge
顺便提一下,我很好奇如何使用GraphQL进行分页。我看到一些仓库有数百个分支,但GitHub在每页最多只能放置100个资源,即使使用GraphQL也是如此... - Jerry Dodge
1
@JerryDodge 我也是一样...只是少了啤酒。这是我第一次真正玩它。我已经添加了有关分页和更多信息的内容。 - Schwern
你的例子使用了pull requests,但这不是我感兴趣的。我正在使用分支,它似乎工作方式完全不同。我尝试在请求的不同相关级别中添加“cursor”,但都没有成功。现在我变成了一个“游标”... - Jerry Dodge
@JerryDodge 它的工作方式与 pullRequests 完全相同。 refs(first:2,refPrefix:“refs / heads /”){edges {cursor {node {name}}}}} - Schwern
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接