在 Github 通过 Travis-CI 使用 httr 以及在本地进行身份验证(本地有效,远程无效)

Authenticate at Github via Travis-CI using httr as well as locally (local works, remote doesn't)

我有一个 Rmd 文件,它使用 httr 访问 Github-API。在本地,如果我在呈现 Rmd:

之前在 R 控制台中 运行 以下内容,我可以使用 Github 进行身份验证
myapp <- oauth_app("APP", key = "xyz", secret = "pqr")
github_token <- oauth2.0_token(oauth_endpoints("github"), myapp)

密钥和秘密是在 Github 创建的,并且在我渲染时存在于我的工作区中,因此 github_token 被拾取并且我可以访问 Github-API 在本地渲染时不会达到访问限制。

现在,相同的 Rmd 也在 Travis-CI 中自动构建,然后在我推送 master 分支时部署到 gh-pages。我有这个有效的 w/o 身份验证,但这将我的 Githhub-API 请求限制限制为 60/小时,我需要通过身份验证获得的更高限制。因此,为此我在 Github 中也设置了一个个人访问令牌 (PAT);设置 PAT 的页面显示 "Personal access tokens function like ordinary OAuth access tokens. They can be used instead of a password for Git over HTTPS, or can be used to authenticate to the API over Basic Authentication".

这是我的 Rmd 的一部分,我在其中尝试检测呈现是本地的还是远程的,并获取适当的令牌。然而,当这是 运行 在 Travis-CI 时,令牌似乎没有被识别,所以我认为我没有正确使用它。

# Figure out the build location, and get the needed token
at_home <- FALSE
at_TCI <- FALSE
token_found <- FALSE
token_OK <- FALSE # not used now/yet

# Check to see if we are at TRAVIS-CI
# This next variable is in the Travis build environment & is a character string
token_value <- Sys.getenv("TRAVIS_CI") 
if (token_value != "") {
  token_found <- TRUE
  at_TCI <- TRUE
}

# Check to see if we are on the local/home machine
# This token is generated interactively via "Web Application Flow",
# and is deposited in the local workspace
# See developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow
# This token has classes 'Token2.0', 'Token', 'R6' <Token2.0>
if (!at_TCI) {
  token_found <- exists("github_token")
  if (token_found) {
    token_value <- github_token
    at_home <- TRUE
  }
}

# See where we stand and act accordingly
if (!token_found) {
  message("Could not retrieve token - GET calls will be rate-limited by Github")
  # TEMPORARY: just use a few lines for faster testing & not blasting GH limits
  DF <- DF[1:5,]
}
if (token_found) {
  set_config(config(token = token_value)) # applies to all GET requests below
}

当我在 Travis-CI 时,我认为 set_config 调用无法正常工作,因为我收到一个似乎来自 GET 调用的错误稍后发生(在 T-CI 上很难排除故障,但 Rmd 在本地工作正常)。这是一个示例 GET 调用,它在 运行 上面的代码片段之后远程失败,但在本地有效:

repoOK[i] <- identical(status_code(GET(DF$repo[i])), 200L)

其中 DF$repo[i] 是 URL。

我是 httr 和 Github-API 的新手,但我花了很多时间试验在 SO 上找到的咒语,以及 Github 文档,但到目前为止远程构建没有成功。因此,我呼吁 SO 社区的怜悯!

编辑:GH repo 完整代码。

编辑 2:赏金期间没有人回答(!)。所以我将在 master 分支上工作。此 branch 具有在本地工作但在 Travis-CI 上失败的代码。此外,此分支已删除所有 Python 内容以避免其他问题并保持内容清洁。该分支在 Travis-CI:

上给出了以下错误

Error in getGHdates(DF$repo[i], "commits") : Github access rate exceeded, try again later

答案似乎是在本地工作时不能使用与在 Travis-CI 远程使用时相同的身份验证方法。为了使 Rmd 在两个位置都能正确呈现,我不得不编写比我希望的更复杂的代码。特别是,对于在本地工作,按如下方式进行身份验证就足够了。

首先,在R控制台运行(同上);

myapp <- oauth_app("APP", key = "xyz", secret = "pqr")
github_token <- oauth2.0_token(oauth_endpoints("github"), myapp)

然后在 Rmd 代码中需要:

# Figure out the build location, and get the needed token
at_home <- FALSE
at_TCI <- FALSE
token_found <- FALSE
where <- NULL

# Check to see if we are at TRAVIS-CI
# This token has class character
token_value <- Sys.getenv("TRAVIS_CI")
if (token_value != "") {
  token_found <- TRUE
  at_TCI <- TRUE
}

# Check to see if we are on the local/home machine
# This token is generated interactively via "Web Application Flow",
# and is deposited in the local workspace with the name github_token before rendering
# See developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow
# This token has classes 'Token2.0', 'Token', 'R6' <Token2.0>
if (!at_TCI) {
  token_found <- exists("github_token")
  if (token_found) {
    token_value <- github_token
    at_home <- TRUE
  }
}

# See where we stand and act accordingly
if (!token_found) {
  message("Could not retrieve token - GET calls will be rate-limited by Github")
  # TEMPORARY: just use a few lines for faster testing & not blasting GH limits
  DF <- DF[1:5,]
}
if (token_found) {
  if (at_home) set_config(config(token = token_value))
  # This is sufficient for at_home and the GET calls elsewhere have a simple form
  if (at_home) where <- "home"
  if (at_TCI) where <- "TCI"
}

if (is.null(where)) stop("I'm lost")

# Report for troubleshooting
# cat("at_home = ", at_home, "\n")
# cat("at_TCI = ", at_TCI, "\n")
# cat("token_found = ", token_found, "\n")

通过这种安排,使用 GET 调用 Github API 可以正常工作。

然而,在 Travis-CI 远程工作时,这种方法不起作用。对于这种情况,需要按照以下方式做一些事情:

for (i in 1:ne) {
  if (!is.na(DF$web[i])) {
    if (at_home) access_string <- DF$web[i]
    if (at_TCI) {
      GH <- grepl("github\.com", DF$web[i])
      if (!GH) access_string <- DF$web[i] # local access
      if (GH) access_string <- paste0(DF$web[i], "?access_token=",
        token_value) # remote access from Travis-CI
    }
    webOK[i] <- identical(status_code(GET(access_string)), 200L)
    webLink[i] <- TRUE
    if (webLink[i] != webOK[i]) badWeb[i] <- TRUE
  }
}

我找到了在 GET 调用 中嵌入令牌的建议。

如果您已经读到这里,祝您在自己的项目上好运!完整代码在此 GH repo.