Skip to content

Commit cec49b6

Browse files
authored
Where possible, use existing github config to determine default branch (#2062)
Fixes #2021
1 parent 2cc9e5a commit cec49b6

File tree

4 files changed

+36
-61
lines changed

4 files changed

+36
-61
lines changed

R/git-default-branch.R

+18-42
Original file line numberDiff line numberDiff line change
@@ -93,39 +93,18 @@ NULL
9393
#' git_default_branch()
9494
#' }
9595
git_default_branch <- function() {
96-
repo <- git_repo()
96+
git_default_branch_(github_remote_config())
97+
}
9798

98-
# TODO: often when we call git_default_branch(), we already have a GitHub
99-
# configuration or target repo, as produced by github_remote_config() or
100-
# target_repo(). In that case, we don't need to start from scratch as we do
101-
# here. But I'm not sure it's worth adding complexity to allow passing this
102-
# data in.
103-
104-
# TODO: this critique feels somewhat mis-placed, i.e. it brings up a general
105-
# concern about a repo's config (or the user's permissions and creds)
106-
# related to whether github_remotes() should be as silent as it is about
107-
# 404s
108-
critique_remote <- function(remote) {
109-
if (remote$is_configured && is.na(remote$default_branch)) {
110-
ui_bullets(c(
111-
"x" = "The {.val {remote$name}} remote is configured, but we can't
112-
determine its default branch.",
113-
" " = "Possible reasons:",
114-
"*" = "The remote repo no longer exists, suggesting the local remote
115-
should be deleted.",
116-
"*" = "We are offline or that specific Git server is down.",
117-
"*" = "You don't have the necessary permission or something is wrong
118-
with your credentials."
119-
))
120-
}
121-
}
99+
# If config is available, we can use it to avoid an additional lookup
100+
# on the GitHub API
101+
git_default_branch_ <- function(cfg) {
102+
repo <- git_repo()
122103

123-
upstream <- git_default_branch_remote("upstream")
104+
upstream <- git_default_branch_remote(cfg, "upstream")
124105
if (is.na(upstream$default_branch)) {
125-
critique_remote(upstream)
126-
origin <- git_default_branch_remote("origin")
106+
origin <- git_default_branch_remote(cfg, "origin")
127107
if (is.na(origin$default_branch)) {
128-
critique_remote(origin)
129108
db_source <- list()
130109
} else {
131110
db_source <- origin
@@ -186,7 +165,7 @@ git_default_branch <- function() {
186165

187166
# returns a whole data structure, because the caller needs the surrounding
188167
# context to produce a helpful error message
189-
git_default_branch_remote <- function(remote = "origin") {
168+
git_default_branch_remote <- function(cfg, remote = "origin") {
190169
repo <- git_repo()
191170
out <- list(
192171
name = remote,
@@ -196,25 +175,22 @@ git_default_branch_remote <- function(remote = "origin") {
196175
default_branch = NA_character_
197176
)
198177

199-
url <- git_remotes()[[remote]]
200-
if (length(url) == 0) {
178+
cfg_remote <- cfg[[remote]]
179+
if (!cfg_remote$is_configured) {
201180
out$is_configured <- FALSE
202181
return(out)
203182
}
183+
204184
out$is_configured <- TRUE
205-
out$url <- url
206-
207-
# TODO: generalize here for GHE hosts that don't include 'github'
208-
parsed <- parse_github_remotes(url)
209-
# if the protocol is ssh, I suppose we can't assume a PAT, i.e. it's better
210-
# to use the Git approach vs. the GitHub API approach
211-
if (grepl("github", parsed$host) && parsed$protocol == "https") {
212-
remote_dat <- github_remotes(remote, github_get = NA)
213-
out$repo_spec <- remote_dat$repo_spec
214-
out$default_branch <- remote_dat$default_branch
185+
out$url <- cfg_remote$url
186+
187+
if (!is.na(cfg_remote$default_branch)) {
188+
out$repo_spec <- cfg_remote$repo_spec
189+
out$default_branch <- cfg_remote$default_branch
215190
return(out)
216191
}
217192

193+
# Fall back to pure git based approach
218194
out$default_branch <- tryCatch(
219195
{
220196
gert::git_fetch(remote = remote, repo = repo, verbose = FALSE)

R/github.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use_github <- function(organisation = NULL,
6161
visibility <- match.arg(visibility)
6262
check_protocol(protocol)
6363
check_uses_git()
64-
default_branch <- git_default_branch()
64+
default_branch <- guess_local_default_branch()
6565
check_current_branch(
6666
is = default_branch,
6767
# glue-ing happens inside check_current_branch(), where `gb` gives the

R/pr.R

+16-17
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pr_init <- function(branch) {
184184
}
185185
}
186186

187-
default_branch <- git_default_branch()
187+
default_branch <- git_default_branch_(cfg)
188188
challenge_non_default_branch(
189189
"Are you sure you want to create a PR branch based on a non-default branch?",
190190
default_branch = default_branch
@@ -237,7 +237,7 @@ pr_resume <- function(branch = NULL) {
237237
ui_bullets(c(
238238
"i" = "No branch specified ... looking up local branches and associated PRs."
239239
))
240-
default_branch <- git_default_branch()
240+
default_branch <- guess_local_default_branch()
241241
branch <- choose_branch(exclude = default_branch)
242242
if (is.null(branch)) {
243243
ui_bullets(c("x" = "Repo doesn't seem to have any non-default branches."))
@@ -375,7 +375,7 @@ pr_push <- function() {
375375
repo <- git_repo()
376376
cfg <- github_remote_config(github_get = TRUE)
377377
check_for_config(cfg, ok_configs = c("ours", "fork"))
378-
default_branch <- git_default_branch()
378+
default_branch <- git_default_branch_(cfg)
379379
check_pr_branch(default_branch)
380380
challenge_uncommitted_changes()
381381

@@ -423,7 +423,7 @@ pr_push <- function() {
423423
pr_pull <- function() {
424424
cfg <- github_remote_config(github_get = TRUE)
425425
check_for_config(cfg)
426-
default_branch <- git_default_branch()
426+
default_branch <- git_default_branch_(cfg)
427427
check_pr_branch(default_branch)
428428
challenge_uncommitted_changes()
429429

@@ -449,11 +449,12 @@ pr_merge_main <- function() {
449449
#' @export
450450
#' @rdname pull-requests
451451
pr_view <- function(number = NULL, target = c("source", "primary")) {
452-
tr <- target_repo(github_get = NA, role = target, ask = FALSE)
452+
cfg <- github_remote_config(github_get = NA)
453+
tr <- target_repo(cfg, github_get = NA, role = target, ask = FALSE)
453454
url <- NULL
454455
if (is.null(number)) {
455456
branch <- git_branch()
456-
default_branch <- git_default_branch()
457+
default_branch <- git_default_branch_(cfg)
457458
if (branch != default_branch) {
458459
url <- pr_url(branch = branch, tr = tr)
459460
if (is.null(url)) {
@@ -491,11 +492,11 @@ pr_view <- function(number = NULL, target = c("source", "primary")) {
491492
#' @export
492493
#' @rdname pull-requests
493494
pr_pause <- function() {
494-
# intentionally naive selection of target repo
495-
tr <- target_repo(github_get = FALSE, ask = FALSE)
495+
cfg <- github_remote_config(github_get = NA)
496+
tr <- target_repo(cfg, github_get = NA, ask = FALSE)
496497

497498
ui_bullets(c("v" = "Switching back to the default branch."))
498-
default_branch <- git_default_branch()
499+
default_branch <- git_default_branch_(cfg)
499500
if (git_branch() == default_branch) {
500501
ui_bullets(c(
501502
"!" = "Already on this repo's default branch ({.val {default_branch}}),
@@ -535,8 +536,10 @@ pr_clean <- function(number = NULL,
535536
withr::defer(rstudio_git_tickle())
536537
mode <- match.arg(mode)
537538
repo <- git_repo()
538-
tr <- target_repo(github_get = NA, role = target, ask = FALSE)
539-
default_branch <- git_default_branch()
539+
540+
cfg <- github_remote_config(github_get = NA)
541+
tr <- target_repo(cfg, github_get = NA, role = target, ask = FALSE)
542+
default_branch <- git_default_branch_(cfg)
540543

541544
if (is.null(number)) {
542545
check_pr_branch(default_branch)
@@ -629,14 +632,10 @@ pr_clean <- function(number = NULL,
629632
# we're in DEFAULT branch of a fork. I wish everyone set up DEFAULT to track the
630633
# DEFAULT branch in the source repo, but this protects us against sub-optimal
631634
# setup.
632-
pr_pull_source_override <- function(tr = NULL, default_branch = NULL) {
633-
# naive selection of target repo; calling function should analyse the config
634-
tr <- tr %||% target_repo(github_get = FALSE, ask = FALSE)
635-
635+
pr_pull_source_override <- function(tr, default_branch) {
636636
# TODO: why does this not use a check_*() function, i.e. shared helper?
637637
# I guess to issue a specific error message?
638638
current_branch <- git_branch()
639-
default_branch <- default_branch %||% git_default_branch()
640639
if (current_branch != default_branch) {
641640
ui_abort("
642641
Internal error: {.fun pr_pull_source_override} should only be used when on
@@ -994,7 +993,7 @@ pr_branch_delete <- function(pr) {
994993
invisible(TRUE)
995994
}
996995

997-
check_pr_branch <- function(default_branch = git_default_branch()) {
996+
check_pr_branch <- function(default_branch) {
998997
# the glue-ing happens inside check_current_branch(), where `gb` gives the
999998
# current git branch
1000999
check_current_branch(

tests/testthat/helper-mocks.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ local_ui_yep <- function(.env = caller_env()) {
2828

2929
local_git_default_branch_remote <- function(.env = caller_env()) {
3030
local_mocked_bindings(
31-
git_default_branch_remote = function(remote) {
31+
git_default_branch_remote = function(cfg, remote) {
3232
list(
3333
name = remote,
3434
is_configured = TRUE,

0 commit comments

Comments
 (0)