Skip to content

Commit

Permalink
remote: introduce set_instance_url
Browse files Browse the repository at this point in the history
Users may want to override the URL on a particular instance of a remote,
instead of updating the configuration.  Previously, users could use a
callback to do this, but this is not particularly idiomatic.
  • Loading branch information
ethomson committed Aug 27, 2021
1 parent 45489a1 commit 6724067
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 3 deletions.
28 changes: 25 additions & 3 deletions include/git2/remote.h
Expand Up @@ -212,18 +212,20 @@ GIT_EXTERN(const char *) git_remote_name(const git_remote *remote);
* Get the remote's url
*
* If url.*.insteadOf has been configured for this URL, it will
* return the modified URL.
* return the modified URL. If `git_remote_set_instance_pushurl`
* has been called for this remote, then that URL will be returned.
*
* @param remote the remote
* @return a pointer to the url
*/
GIT_EXTERN(const char *) git_remote_url(const git_remote *remote);

/**
* Get the remote's url for pushing
* Get the remote's url for pushing.
*
* If url.*.pushInsteadOf has been configured for this URL, it
* will return the modified URL.
* will return the modified URL. If `git_remote_set_instance_pushurl`
* has been called for this remote, then that URL will be returned.
*
* @param remote the remote
* @return a pointer to the url or NULL if no special url for pushing is set
Expand Down Expand Up @@ -257,6 +259,26 @@ GIT_EXTERN(int) git_remote_set_url(git_repository *repo, const char *remote, con
*/
GIT_EXTERN(int) git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url);

/**
* Set the url for this particular url instance. The URL in the
* configuration will be ignored, and will not be changed.
*
* @param remote the remote's name
* @param url the url to set
* @return 0 or an error value
*/
GIT_EXTERN(int) git_remote_set_instance_url(git_remote *remote, const char *url);

/**
* Set the push url for this particular url instance. The URL in the
* configuration will be ignored, and will not be changed.
*
* @param remote the remote's name
* @param url the url to set
* @return 0 or an error value
*/
GIT_EXTERN(int) git_remote_set_instance_pushurl(git_remote *remote, const char *url);

/**
* Add a fetch refspec to the remote's configuration
*
Expand Down
32 changes: 32 additions & 0 deletions src/remote.c
Expand Up @@ -600,6 +600,22 @@ const char *git_remote_url(const git_remote *remote)
return remote->url;
}

int git_remote_set_instance_url(git_remote *remote, const char *url)
{
char *tmp;

GIT_ASSERT_ARG(remote);
GIT_ASSERT_ARG(url);

if ((tmp = git__strdup(url)) == NULL)
return -1;

git__free(remote->url);
remote->url = tmp;

return 0;
}

static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
{
git_config *cfg;
Expand Down Expand Up @@ -645,6 +661,22 @@ const char *git_remote_pushurl(const git_remote *remote)
return remote->pushurl;
}

int git_remote_set_instance_pushurl(git_remote *remote, const char *url)
{
char *tmp;

GIT_ASSERT_ARG(remote);
GIT_ASSERT_ARG(url);

if ((tmp = git__strdup(url)) == NULL)
return -1;

git__free(remote->pushurl);
remote->pushurl = tmp;

return 0;
}

int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
{
return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
Expand Down
45 changes: 45 additions & 0 deletions tests/network/remote/remotes.c
Expand Up @@ -121,6 +121,51 @@ void test_network_remote_remotes__urlresolve_passthrough(void)
git_buf_dispose(&url);
}

void test_network_remote_remotes__instance_url(void)
{
git_buf url = GIT_BUF_INIT;
const char *orig_url = "git://github.com/libgit2/libgit2";

cl_assert_equal_s(git_remote_name(_remote), "test");
cl_assert_equal_s(git_remote_url(_remote), orig_url);

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
cl_assert_equal_s(url.ptr, orig_url);
git_buf_clear(&url);

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
cl_assert_equal_s(url.ptr, orig_url);
git_buf_clear(&url);

/* Setting the instance url updates the fetch and push URLs */
git_remote_set_instance_url(_remote, "https://github.com/new/remote/url");
cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
cl_assert_equal_p(git_remote_pushurl(_remote), NULL);

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
git_buf_clear(&url);

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
git_buf_clear(&url);

/* Setting the instance push url updates only the push URL */
git_remote_set_instance_pushurl(_remote, "https://github.com/new/push/url");
cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
cl_assert_equal_s(git_remote_pushurl(_remote), "https://github.com/new/push/url");

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
git_buf_clear(&url);

cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
cl_assert_equal_s(url.ptr, "https://github.com/new/push/url");
git_buf_clear(&url);

git_buf_dispose(&url);
}

void test_network_remote_remotes__pushurl(void)
{
const char *name = git_remote_name(_remote);
Expand Down

0 comments on commit 6724067

Please sign in to comment.