Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli: git: add remote set-url #3937

Merged
merged 1 commit into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj prev` and `jj next` have gained a `--conflict` flag which moves you
to the next conflict in a child commit.

* New command `jj git remote set-url` that sets the url of a git remote.

### Fixed bugs

## [0.18.0] - 2024-06-05
Expand Down
4 changes: 4 additions & 0 deletions cli/src/commands/git/remote/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ pub mod add;
pub mod list;
pub mod remove;
pub mod rename;
pub mod set_url;

use clap::Subcommand;

use self::add::{cmd_remote_add, AddArgs};
use self::list::{cmd_remote_list, ListArgs};
use self::remove::{cmd_remote_remove, RemoveArgs};
use self::rename::{cmd_remote_rename, RenameArgs};
use self::set_url::{cmd_remote_set_url, SetUrlArgs};
use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::ui::Ui;
Expand All @@ -36,6 +38,7 @@ pub enum RemoteCommand {
List(ListArgs),
Remove(RemoveArgs),
Rename(RenameArgs),
SetUrl(SetUrlArgs),
}

pub fn cmd_git_remote(
Expand All @@ -48,5 +51,6 @@ pub fn cmd_git_remote(
RemoteCommand::List(args) => cmd_remote_list(ui, command, args),
RemoteCommand::Remove(args) => cmd_remote_remove(ui, command, args),
RemoteCommand::Rename(args) => cmd_remote_rename(ui, command, args),
RemoteCommand::SetUrl(args) => cmd_remote_set_url(ui, command, args),
}
}
42 changes: 42 additions & 0 deletions cli/src/commands/git/remote/set_url.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2024 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use jj_lib::git;
use jj_lib::repo::Repo;

use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::git_util::get_git_repo;
use crate::ui::Ui;

/// Set the URL of a Git remote
#[derive(clap::Args, Clone, Debug)]
pub struct SetUrlArgs {
/// The remote's name
remote: String,
/// The desired url for `remote`
url: String,
}

pub fn cmd_remote_set_url(
ui: &mut Ui,
command: &CommandHelper,
args: &SetUrlArgs,
) -> Result<(), CommandError> {
let workspace_command = command.workspace_helper(ui)?;
let repo = workspace_command.repo();
let git_repo = get_git_repo(repo.store())?;
git::set_remote_url(&git_repo, &args.remote, &args.url)?;
Ok(())
}
15 changes: 15 additions & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ This document contains the help content for the `jj` command-line program.
* [`jj git remote list`↴](#jj-git-remote-list)
* [`jj git remote remove`↴](#jj-git-remote-remove)
* [`jj git remote rename`↴](#jj-git-remote-rename)
* [`jj git remote set-url`↴](#jj-git-remote-set-url)
* [`jj init`↴](#jj-init)
* [`jj interdiff`↴](#jj-interdiff)
* [`jj log`↴](#jj-log)
Expand Down Expand Up @@ -955,6 +956,7 @@ The Git repo will be a bare git repo stored inside the `.jj/` directory.
* `list` — List Git remotes
* `remove` — Remove a Git remote and forget its branches
* `rename` — Rename a Git remote
* `set-url` — Set the URL of a Git remote



Expand Down Expand Up @@ -1004,6 +1006,19 @@ Rename a Git remote



## `jj git remote set-url`

Set the URL of a Git remote

**Usage:** `jj git remote set-url <REMOTE> <URL>`

###### **Arguments:**

* `<REMOTE>` — The remote's name
* `<URL>` — The desired url for `remote`



## `jj init`

Create a new repo in the given directory
Expand Down
54 changes: 54 additions & 0 deletions cli/tests/test_git_remotes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,60 @@ fn test_git_remote_add() {
"###);
}

#[test]
fn test_git_remote_set_url() {
let test_env = TestEnvironment::default();

test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(
&repo_path,
&["git", "remote", "add", "foo", "http://example.com/repo/foo"],
);
let stderr = test_env.jj_cmd_failure(
&repo_path,
&[
"git",
"remote",
"set-url",
"bar",
"http://example.com/repo/bar",
],
);
insta::assert_snapshot!(stderr, @r###"
Error: No git remote named 'bar'
"###);
let stderr = test_env.jj_cmd_failure(
&repo_path,
&[
"git",
"remote",
"set-url",
"git",
"http://example.com/repo/git",
],
);
insta::assert_snapshot!(stderr, @r###"
Error: Git remote named 'git' is reserved for local Git repository
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(
&repo_path,
&[
"git",
"remote",
"set-url",
"foo",
"http://example.com/repo/bar",
],
);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @"");
let stdout = test_env.jj_cmd_success(&repo_path, &["git", "remote", "list"]);
insta::assert_snapshot!(stdout, @r###"
foo http://example.com/repo/bar
"###);
}

#[test]
fn test_git_remote_rename() {
let test_env = TestEnvironment::default();
Expand Down
26 changes: 26 additions & 0 deletions lib/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,32 @@ pub fn rename_remote(
Ok(())
}

pub fn set_remote_url(
git_repo: &git2::Repository,
remote_name: &str,
new_remote_url: &str,
) -> Result<(), GitRemoteManagementError> {
if remote_name == REMOTE_NAME_FOR_LOCAL_GIT_REPO {
return Err(GitRemoteManagementError::RemoteReservedForLocalGitRepo);
}

// Repository::remote_set_url() doesn't ensure the remote exists, it just
// creates it if it's missing.
// Therefore ensure it exists first
git_repo.find_remote(remote_name).map_err(|err| {
if is_remote_not_found_err(&err) {
GitRemoteManagementError::NoSuchRemote(remote_name.to_owned())
} else {
GitRemoteManagementError::InternalGitError(err)
}
})?;

git_repo
.remote_set_url(remote_name, new_remote_url)
.map_err(GitRemoteManagementError::InternalGitError)?;
Ok(())
}

fn rename_remote_refs(mut_repo: &mut MutableRepo, old_remote_name: &str, new_remote_name: &str) {
mut_repo.rename_remote(old_remote_name, new_remote_name);
let prefix = format!("refs/remotes/{old_remote_name}/");
Expand Down