Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ from*/
logs/
dist/
global-cache/
drift-reviews/
drift-reviews/

temp-pkg
2 changes: 2 additions & 0 deletions src/cli/commands/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const INITIAL_CONFIG: &str = r#"[project]
name = "%project_name%"
r_version = "%r_version%"
%use_devel%
# Optional: base URL for `rv add owner/repo` shorthand (defaults to https://github.com).
# git_shorthand_base_url = "https://github.example.com"
Comment thread
Keats marked this conversation as resolved.
# A list of repositories to fetch packages from. Order matters: we will try to get a package from each repository in order.
# The alias is only used in this file if you want to specifically require a dependency to come from a certain repository.
# Example: { alias = "PPM", url = "https://packagemanager.posit.co/cran/latest" },
Expand Down
2 changes: 1 addition & 1 deletion src/cli/resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn resolve_dependencies(
let resolution = context.resolve(resolve_mode);

if !resolution.is_success() && exit_on_failure {
eprintln!("Failed to resolve all dependencies");
eprintln!("Failed to resolve all dependencies:");
let req_error_messages = resolution.req_error_messages();

for d in &resolution.failed {
Expand Down
118 changes: 115 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::str::FromStr;

use crate::SystemInfo;
use crate::consts::LOCKFILE_NAME;
use crate::dependency_edit::DEFAULT_GIT_SHORTHAND_BASE_URL;
use crate::git::url::GitUrl;
use crate::lockfile::Source;
use crate::package::{Version, deserialize_version, serialize_version};
Expand Down Expand Up @@ -84,6 +85,8 @@ pub enum ConfigDependency {
commit: Option<String>,
tag: Option<String>,
branch: Option<String>,
#[serde(default)]
reference: Option<String>,
directory: Option<String>,
name: String,
#[serde(default)]
Expand Down Expand Up @@ -176,13 +179,15 @@ impl ConfigDependency {
directory,
tag,
branch,
reference,
..
} => Source::Git {
git,
sha,
directory,
tag,
branch,
reference,
},
_ => unreachable!(),
}
Expand Down Expand Up @@ -351,6 +356,10 @@ pub(crate) struct Project {
/// Package-specific configure.args with system targeting
#[serde(default)]
pub configure_args: HashMap<String, Vec<ConfigureArgsRule>>,
/// Base URL used by `rv add <owner>/<repo>` shorthand.
/// Defaults to https://github.com when not specified.
#[serde(default)]
git_shorthand_base_url: Option<String>,
}

// That's the way to do it with serde :/
Expand Down Expand Up @@ -424,17 +433,46 @@ impl Config {
tag,
branch,
commit,
reference,
..
} => match (tag.is_some(), branch.is_some(), commit.is_some()) {
(true, false, false) | (false, true, false) | (false, false, true) => (),
} => match (
tag.is_some(),
branch.is_some(),
commit.is_some(),
reference.is_some(),
) {
(true, false, false, false)
| (false, true, false, false)
| (false, false, true, false)
| (false, false, false, true) => (),
_ => {
errors.push(format!("A git dependency `{git}` requires ons and only one of tag/branch/commit set. "));
errors.push(format!(
"A git dependency `{git}` requires one and only one of tag/branch/commit/reference set."
));
}
},
_ => (),
}
}

if let Some(base_url) = self.project.git_shorthand_base_url.as_deref() {
let base_url = base_url.trim();
if base_url.is_empty() {
errors.push("`project.git_shorthand_base_url` cannot be empty.".to_string());
} else {
let probe_url = if base_url.ends_with(':') {
format!("{base_url}owner/repo")
} else {
format!("{}/owner/repo", base_url.trim_end_matches('/'))
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that the same for gitlab/gitea?

if let Err(e) = GitUrl::try_from(probe_url.as_str()) {
errors.push(format!(
"Invalid `project.git_shorthand_base_url` `{base_url}`: {e}"
));
}
}
}

if !errors.is_empty() {
return Err(ConfigLoadError {
path: Path::new(".").into(),
Expand Down Expand Up @@ -509,6 +547,13 @@ impl Config {
pub fn configure_args(&self) -> &HashMap<String, Vec<ConfigureArgsRule>> {
&self.project.configure_args
}

pub fn git_shorthand_base_url(&self) -> &str {
self.project
.git_shorthand_base_url
.as_deref()
.unwrap_or(DEFAULT_GIT_SHORTHAND_BASE_URL)
}
}

impl FromStr for Config {
Expand Down Expand Up @@ -582,4 +627,71 @@ repositories = []
deserialized.r_version().original
);
}

#[test]
fn git_dependency_allows_reference_field() {
let toml_str = r#"
[project]
name = "test"
r_version = "4.4"
repositories = []
dependencies = [
{ name = "cli", git = "https://github.com/r-lib/cli", reference = "main" }
]
"#;
let config = Config::from_str(toml_str).unwrap();
match &config.dependencies()[0] {
ConfigDependency::Git { reference, .. } => {
assert_eq!(reference.as_deref(), Some("main"));
}
_ => panic!("Expected a git dependency"),
}
}

#[test]
fn git_shorthand_base_url_defaults_and_overrides() {
let default_toml = r#"
[project]
name = "test"
r_version = "4.4"
repositories = []
"#;
let default_config = Config::from_str(default_toml).unwrap();
assert_eq!(
default_config.git_shorthand_base_url(),
crate::dependency_edit::DEFAULT_GIT_SHORTHAND_BASE_URL
);

let custom_toml = r#"
[project]
name = "test"
r_version = "4.4"
repositories = []
git_shorthand_base_url = "https://git.example.com/scm"
"#;
let custom_config = Config::from_str(custom_toml).unwrap();
assert_eq!(
custom_config.git_shorthand_base_url(),
"https://git.example.com/scm"
);
}

#[test]
fn invalid_git_shorthand_base_url_errors() {
let toml_str = r#"
[project]
name = "test"
r_version = "4.4"
repositories = []
git_shorthand_base_url = "git.example.com"
"#;
let err = Config::from_str(toml_str).unwrap_err();
assert!(
err.source
.to_string()
.contains("Invalid `project.git_shorthand_base_url`"),
"unexpected error: {}",
err.source
);
}
}
Loading