Skip to content

Commit ff0f02b

Browse files
authored
feat: add add argument to git_config_set() (#261)
1 parent e895909 commit ff0f02b

10 files changed

Lines changed: 97 additions & 49 deletions

File tree

NAMESPACE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ useDynLib(gert,R_git_remote_ls)
144144
useDynLib(gert,R_git_remote_push)
145145
useDynLib(gert,R_git_remote_refspecs)
146146
useDynLib(gert,R_git_remote_remove)
147-
useDynLib(gert,R_git_remote_set_pushurl)
148147
useDynLib(gert,R_git_remote_set_url)
149148
useDynLib(gert,R_git_repository_add)
150149
useDynLib(gert,R_git_repository_clone)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# gert (development version)
22

3+
- `git_remote_set_pushurl()` gains an `add` argument to append push URLs instead of replacing them. (@robitalec, #128)
34
- Fix `git_info()` for the case when no upstream is configured (@mpage, #263)
45
- `git_branch_create()`: `force` now also applies to the checkout step, allowing branch creation even when local changes would be overwritten (@MichaelChirico, #177).
56
- Improve manual pages (@olivroy, #227)

R/config.R

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#' option is determined from global or local config.
2222
#' * `git_config_global()`: a `data.frame`, as for `git_config()`, except only
2323
#' for global Git options.
24-
#' * `git_config_set()`, `git_config_global_set()`: The previous value of
24+
#' * `git_config_set()`, `git_config_global_set()`: The previous value(s) of
2525
#' `name` in local or global config, respectively. If this option was
2626
#' previously unset, returns `NULL`. Returns invisibly.
2727
#'
@@ -76,12 +76,18 @@ git_config_global <- function() {
7676
#' @param name Name of the option to set
7777
#' @param value Value to set. Must be a string, logical, number or `NULL` (to
7878
#' unset).
79-
git_config_set <- function(name, value, repo = '.') {
79+
#' @param add if `TRUE`, append a new entry for `name` instead of replacing
80+
#' existing one(s). Equivalent to `git config --add`. Only supported for
81+
#' string values.
82+
git_config_set <- function(name, value, add = FALSE, repo = '.') {
83+
if (!is.logical(add) || length(add) != 1) {
84+
stop("Argument add must be a logical of length 1.", call. = FALSE)
85+
}
8086
repo <- git_open(repo)
8187
name <- as.character(name)
8288
orig_cfg <- git_config(repo = repo)
8389
out <- orig_cfg$value[orig_cfg$name == name & orig_cfg$level == "local"]
84-
.Call(R_git_config_set, repo, name, value)
90+
.Call(R_git_config_set, repo, name, value, add)
8591
if (length(out) > 0) {
8692
invisible(out)
8793
} else {
@@ -91,10 +97,10 @@ git_config_set <- function(name, value, repo = '.') {
9197

9298
#' @export
9399
#' @rdname git_config
94-
git_config_global_set <- function(name, value) {
100+
git_config_global_set <- function(name, value, add = FALSE) {
95101
orig_cfg <- git_config_global()
96102
out <- orig_cfg$value[orig_cfg$name == name]
97-
.Call(R_git_config_set, NULL, name, value)
103+
.Call(R_git_config_set, NULL, name, value, add)
98104
if (length(out) > 0) {
99105
invisible(out)
100106
} else {

R/remotes.R

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,27 @@ git_remote_set_url <- function(url, remote = NULL, repo = '.') {
6868

6969
#' @export
7070
#' @rdname git_remote
71-
#' @useDynLib gert R_git_remote_set_pushurl
72-
git_remote_set_pushurl <- function(url, remote = NULL, repo = '.') {
71+
#' @param add if `TRUE`, append the push URL instead of replacing it.
72+
#' Equivalent to `git remote set-url --push --add`.
73+
git_remote_set_pushurl <- function(
74+
url,
75+
remote = NULL,
76+
add = FALSE,
77+
repo = '.'
78+
) {
7379
repo <- git_open(repo)
7480
remote <- as.character(remote)
7581
if (!length(remote)) {
7682
remote <- git_info(repo = repo)$remote
7783
}
7884
url <- as.character(url)
79-
.Call(R_git_remote_set_pushurl, repo, remote, url)
80-
invisible()
85+
86+
git_config_set(
87+
paste0("remote.", remote, ".pushurl"),
88+
url,
89+
repo = repo,
90+
add = add
91+
)
8192
}
8293

8394
#' @export

man/git_config.Rd

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/git_remote.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/branch.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,7 @@ SEXP R_git_remote_set_url(SEXP ptr, SEXP name, SEXP url){
236236
return out;
237237
}
238238

239-
SEXP R_git_remote_set_pushurl(SEXP ptr, SEXP name, SEXP url){
240-
git_remote * remote = NULL;
241-
const char *curl = Rf_length(url) ? CHAR(STRING_ELT(url, 0)) : NULL;
242-
const char *cname = CHAR(STRING_ELT(name, 0));
243-
git_repository *repo = get_git_repository(ptr);
244-
bail_if(git_remote_lookup(&remote, repo, cname), "git_remote_lookup");
245-
bail_if(git_remote_set_pushurl(repo, cname, curl), "git_remote_set_url");
246-
SEXP out = safe_string(git_remote_pushurl(remote));
247-
git_remote_free(remote);
248-
return out;
249-
}
239+
250240

251241
SEXP R_git_remote_remove(SEXP ptr, SEXP name){
252242
const char *cname = CHAR(STRING_ELT(name, 0));

src/config.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,33 +67,39 @@ SEXP R_git_config_list(SEXP ptr){
6767
return out;
6868
}
6969

70-
SEXP R_git_config_set(SEXP ptr, SEXP name, SEXP value){
70+
SEXP R_git_config_set(SEXP ptr, SEXP name, SEXP value, SEXP add){
7171
git_config *cfg = NULL;
7272
const char *cname = CHAR(STRING_ELT(name, 0));
7373
if(Rf_isNull(ptr)) {
7474
bail_if(git_config_open_default(&cfg), "git_config_open_default");
7575
} else {
7676
bail_if(git_repository_config(&cfg, get_git_repository(ptr)),"git_repository_config");
7777
}
78-
switch(TYPEOF(value)){
79-
case STRSXP:
80-
bail_if(git_config_set_string(cfg, cname, CHAR(STRING_ELT(value, 0))), "git_config_set_string");
81-
break;
82-
case LGLSXP:
83-
bail_if(git_config_set_bool(cfg, cname, Rf_asLogical(value)), "git_config_set_bool");
84-
break;
85-
case INTSXP:
86-
bail_if(git_config_set_int32(cfg, cname, Rf_asInteger(value)), "git_config_set_int32");
87-
break;
88-
case REALSXP:
89-
//NB: gets stored as string anyway
90-
bail_if(git_config_set_int64(cfg, cname, (int64_t) Rf_asReal(value)), "git_config_set_int64");
91-
break;
92-
case NILSXP:
93-
bail_if(git_config_delete_entry(cfg, cname), "git_config_delete_entry");
94-
break;
95-
default:
96-
Rf_error("Option value must be string, boolean, number, or NULL");
78+
if(Rf_asLogical(add)) {
79+
if(TYPEOF(value) != STRSXP)
80+
Rf_error("add = TRUE only supported for string values");
81+
bail_if(git_config_set_multivar(cfg, cname, "^$", CHAR(STRING_ELT(value, 0))), "git_config_set_multivar");
82+
} else {
83+
switch(TYPEOF(value)){
84+
case STRSXP:
85+
bail_if(git_config_set_string(cfg, cname, CHAR(STRING_ELT(value, 0))), "git_config_set_string");
86+
break;
87+
case LGLSXP:
88+
bail_if(git_config_set_bool(cfg, cname, Rf_asLogical(value)), "git_config_set_bool");
89+
break;
90+
case INTSXP:
91+
bail_if(git_config_set_int32(cfg, cname, Rf_asInteger(value)), "git_config_set_int32");
92+
break;
93+
case REALSXP:
94+
//NB: gets stored as string anyway
95+
bail_if(git_config_set_int64(cfg, cname, (int64_t) Rf_asReal(value)), "git_config_set_int64");
96+
break;
97+
case NILSXP:
98+
bail_if(git_config_delete_entry(cfg, cname), "git_config_delete_entry");
99+
break;
100+
default:
101+
Rf_error("Option value must be string, boolean, number, or NULL");
102+
}
97103
}
98104
git_config_free(cfg);
99105
return R_NilValue;

src/init.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern SEXP R_git_commit_info(SEXP, SEXP);
3030
extern SEXP R_git_commit_log(SEXP, SEXP, SEXP, SEXP, SEXP);
3131
extern SEXP R_git_commit_stats(SEXP, SEXP);
3232
extern SEXP R_git_config_list(SEXP);
33-
extern SEXP R_git_config_set(SEXP, SEXP, SEXP);
33+
extern SEXP R_git_config_set(SEXP, SEXP, SEXP, SEXP);
3434
extern SEXP R_git_conflict_list(SEXP);
3535
extern SEXP R_git_create_branch(SEXP, SEXP, SEXP, SEXP, SEXP);
3636
extern SEXP R_git_delete_branch(SEXP, SEXP);
@@ -51,7 +51,6 @@ extern SEXP R_git_remote_ls(SEXP, SEXP, SEXP, SEXP, SEXP);
5151
extern SEXP R_git_remote_push(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
5252
extern SEXP R_git_remote_refspecs(SEXP, SEXP);
5353
extern SEXP R_git_remote_remove(SEXP, SEXP);
54-
extern SEXP R_git_remote_set_pushurl(SEXP, SEXP, SEXP);
5554
extern SEXP R_git_remote_set_url(SEXP, SEXP, SEXP);
5655
extern SEXP R_git_revert(SEXP, SEXP);
5756
extern SEXP R_git_repository_add(SEXP, SEXP, SEXP);
@@ -115,7 +114,7 @@ static const R_CallMethodDef CallEntries[] = {
115114
{"R_git_commit_log", (DL_FUNC) &R_git_commit_log, 5},
116115
{"R_git_commit_stats", (DL_FUNC) &R_git_commit_stats, 2},
117116
{"R_git_config_list", (DL_FUNC) &R_git_config_list, 1},
118-
{"R_git_config_set", (DL_FUNC) &R_git_config_set, 3},
117+
{"R_git_config_set", (DL_FUNC) &R_git_config_set, 4},
119118
{"R_git_conflict_list", (DL_FUNC) &R_git_conflict_list, 1},
120119
{"R_git_create_branch", (DL_FUNC) &R_git_create_branch, 5},
121120
{"R_git_delete_branch", (DL_FUNC) &R_git_delete_branch, 2},
@@ -136,7 +135,6 @@ static const R_CallMethodDef CallEntries[] = {
136135
{"R_git_remote_push", (DL_FUNC) &R_git_remote_push, 6},
137136
{"R_git_remote_refspecs", (DL_FUNC) &R_git_remote_refspecs, 2},
138137
{"R_git_remote_remove", (DL_FUNC) &R_git_remote_remove, 2},
139-
{"R_git_remote_set_pushurl", (DL_FUNC) &R_git_remote_set_pushurl, 3},
140138
{"R_git_remote_set_url", (DL_FUNC) &R_git_remote_set_url, 3},
141139
{"R_git_repository_add", (DL_FUNC) &R_git_repository_add, 3},
142140
{"R_git_repository_clone", (DL_FUNC) &R_git_repository_clone, 8},

tests/testthat/test-remotes.R

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
test_that("git_remote_set_pushurl with add = TRUE appends push URLs", {
2+
repo <- git_init(tempfile("gert-tests-pushurl"))
3+
on.exit(unlink(repo, recursive = TRUE))
4+
configure_local_user(repo)
5+
6+
git_remote_add("https://example.com/fetch", name = "origin", repo = repo)
7+
8+
git_remote_set_pushurl("https://example.com/push1", remote = "origin", repo = repo)
9+
git_remote_set_pushurl("https://example.com/push2", remote = "origin", add = TRUE, repo = repo)
10+
11+
cfg <- git_config(repo = repo)
12+
pushurls <- cfg$value[cfg$name == "remote.origin.pushurl"]
13+
expect_setequal(pushurls, c("https://example.com/push1", "https://example.com/push2"))
14+
})
15+
16+
test_that("git_remote_set_pushurl without add replaces push URL", {
17+
repo <- git_init(tempfile("gert-tests-pushurl-replace"))
18+
on.exit(unlink(repo, recursive = TRUE))
19+
configure_local_user(repo)
20+
21+
git_remote_add("https://example.com/fetch", name = "origin", repo = repo)
22+
23+
git_remote_set_pushurl("https://example.com/push1", remote = "origin", repo = repo)
24+
git_remote_set_pushurl("https://example.com/push2", remote = "origin", repo = repo)
25+
26+
cfg <- git_config(repo = repo)
27+
pushurls <- cfg$value[cfg$name == "remote.origin.pushurl"]
28+
expect_equal(pushurls, "https://example.com/push2")
29+
})
30+
131
test_that("remotes from new repo", {
232
skip_if_offline('github.com')
333
repo <- git_init(tempfile("gert-tests-remote"))

0 commit comments

Comments
 (0)