Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 3 additions & 3 deletions e2e/backend/test_github_versions_host_no_api
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ wait_for_file "$SERVER_PORT_FILE" "GitHub API blocker port file" 30 "$SERVER_PID
SERVER_PORT=$(cat "$SERVER_PORT_FILE")

rm -rf "$MISE_CACHE_DIR/github"
mise uninstall github:jdx/mise-test-fixtures 2>/dev/null || true
mise uninstall communique 2>/dev/null || true

cat <<EOF >mise.toml
[settings]
url_replacements = { "https://api.github.com" = "http://127.0.0.1:$SERVER_PORT" }

[tools]
"github:jdx/mise-test-fixtures" = { version = "1.0.0", asset_pattern = "hello-world-1.0.0.tar.gz", bin_path = "hello-world-1.0.0/bin", postinstall = "chmod +x \$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world" }
communique = "1.1.3"
EOF

assert_succeed "mise install"
assert_contains "mise x -- hello-world" "hello world"
assert_contains "mise x -- communique --version" "communique 1.1.3"

if compgen -G "$HEADERS_LOG_DIR/request_*.json" >/dev/null; then
cat "$HEADERS_LOG_DIR"/request_*.json
Expand Down
77 changes: 70 additions & 7 deletions src/backend/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use crate::backend::static_helpers::{
get_filename_from_url, install_artifact, lookup_platform_key, lookup_with_fallback,
template_string, try_with_v_prefix, try_with_v_prefix_and_repo, verify_artifact,
};
use crate::backend::{MISE_BINS_DIR, SecurityFeature, runtime_path_for_install_path};
use crate::backend::{
MISE_BINS_DIR, SecurityFeature, backend_arg_matches_registry_backend,
runtime_path_for_install_path,
};
use crate::cli::args::{BackendArg, ToolVersionType};
use crate::config::{Config, Settings};
use crate::file;
Expand Down Expand Up @@ -392,7 +395,10 @@ impl Backend for UnifiedGitBackend {
}
}
} else {
match github::get_release_for_url(&api_url, &repo, "latest").await {
match self
.get_github_release_for_url(&api_url, &repo, "latest")
.await
{
Ok(r) => Some(r.tag_name),
Err(e) => {
debug!("Failed to fetch latest GitHub release for {repo}: {e}");
Expand Down Expand Up @@ -426,10 +432,19 @@ impl Backend for UnifiedGitBackend {
let api_url = opts.api_url();
let version_prefix = opts.version_prefix();

let use_versions_host = self.use_versions_host_for_github_metadata();
match try_with_v_prefix_and_repo(version, version_prefix, Some(&repo), |candidate| {
let api_url = api_url.clone();
let repo = repo.clone();
async move { github::get_release_for_url(&api_url, &repo, &candidate).await }
async move {
github::get_release_for_url_with_versions_host(
&api_url,
&repo,
&candidate,
use_versions_host,
)
.await
}
})
.await
{
Expand Down Expand Up @@ -605,6 +620,25 @@ impl UnifiedGitBackend {
}
}

fn use_versions_host_for_github_metadata(&self) -> bool {
backend_arg_matches_registry_backend(&self.ba)
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.

async fn get_github_release_for_url(
&self,
api_url: &str,
repo: &str,
tag: &str,
) -> Result<github::GithubRelease> {
github::get_release_for_url_with_versions_host(
api_url,
repo,
tag,
self.use_versions_host_for_github_metadata(),
)
.await
}

/// Detect what provenance type is available for a release by checking its assets
/// and querying the GitHub attestation API.
async fn detect_provenance_type(
Expand All @@ -620,11 +654,20 @@ impl UnifiedGitBackend {
let version = &tv.version;
let version_prefix = opts.version_prefix();

let use_versions_host = self.use_versions_host_for_github_metadata();
let release =
try_with_v_prefix_and_repo(version, version_prefix, Some(repo), |candidate| {
let api_url = api_url.to_string();
let repo = repo.to_string();
async move { github::get_release_for_url(&api_url, &repo, &candidate).await }
async move {
github::get_release_for_url_with_versions_host(
&api_url,
&repo,
&candidate,
use_versions_host,
)
.await
}
})
.await
.ok();
Expand Down Expand Up @@ -782,11 +825,20 @@ impl UnifiedGitBackend {
if settings.slsa && settings.github.slsa {
let version = &tv.version;
let version_prefix = opts.version_prefix();
let use_versions_host = self.use_versions_host_for_github_metadata();
let release =
try_with_v_prefix_and_repo(version, version_prefix, Some(repo), |candidate| {
let api_url = api_url.to_string();
let repo = repo.to_string();
async move { github::get_release_for_url(&api_url, &repo, &candidate).await }
async move {
github::get_release_for_url_with_versions_host(
&api_url,
&repo,
&candidate,
use_versions_host,
)
.await
}
})
.await?;

Expand Down Expand Up @@ -1181,7 +1233,9 @@ impl UnifiedGitBackend {
version: &str,
target: &PlatformTarget,
) -> Result<ReleaseAsset> {
let release = github::get_release_for_url(api_url, repo, version).await?;
let release = self
.get_github_release_for_url(api_url, repo, version)
.await?;
let available_assets: Vec<String> = release.assets.iter().map(|a| a.name.clone()).collect();

// Build asset list with URLs for checksum fetching
Expand Down Expand Up @@ -1884,11 +1938,20 @@ impl UnifiedGitBackend {

// Try to get the release (with version prefix support)
let version_prefix = opts.version_prefix();
let use_versions_host = self.use_versions_host_for_github_metadata();
let release =
match try_with_v_prefix_and_repo(version, version_prefix, Some(&repo), |candidate| {
let api_url = api_url.to_string();
let repo = repo.clone();
async move { github::get_release_for_url(&api_url, &repo, &candidate).await }
async move {
github::get_release_for_url_with_versions_host(
&api_url,
&repo,
&candidate,
use_versions_host,
)
.await
}
})
.await
{
Expand Down
24 changes: 17 additions & 7 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ pub type VersionCacheManager = CacheManager<Vec<VersionInfo>>;

pub(crate) const MISE_BINS_DIR: &str = ".mise-bins";

pub(crate) fn backend_arg_matches_registry_backend(ba: &BackendArg) -> bool {
let full = ba.full();
REGISTRY
.get(ba.short.as_str())
.is_some_and(|rt| rt.backends().iter().any(|b| *b == full))
}
Comment thread
cursor[bot] marked this conversation as resolved.

const VERSIONS_HOST_LOCAL_OPT_SOURCES: &[ToolOptionSource] = &[
ToolOptionSource::InstallManifest,
ToolOptionSource::BackendAlias,
Expand Down Expand Up @@ -1140,18 +1147,21 @@ pub trait Backend: Debug + Send + Sync {
// the registry's default. When a user aliases a tool to a different backend
// (e.g. `php = "github:verzly/php"`), the versions host would return versions
// from the registry's default backend which may not match the aliased backend.
let full = ba.full();
if let Some(rt) = REGISTRY.get(ba.short.as_str()) {
let is_registry_backend = rt.backends().iter().any(|b| *b == full);
if !is_registry_backend {
if REGISTRY.contains_key(ba.short.as_str()) {
if !backend_arg_matches_registry_backend(&ba) {
trace!(
"Skipping versions host for {} because backend {} is not the registry default",
ba.short, full
ba.short,
ba.full()
);
}
is_registry_backend
backend_arg_matches_registry_backend(&ba)
} else {
true // Not in registry, safe to use versions host
trace!(
"Skipping versions host for {} because it is not in the registry",
ba.short
);
false
}
};

Expand Down
37 changes: 29 additions & 8 deletions src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,18 @@ pub async fn get_release(repo: &str, tag: &str) -> Result<GithubRelease> {
.await
}

pub async fn get_release_for_url(api_url: &str, repo: &str, tag: &str) -> Result<GithubRelease> {
let key = format!("{api_url}-{repo}-{tag}").to_kebab_case();
pub async fn get_release_for_url_with_versions_host(
api_url: &str,
repo: &str,
tag: &str,
use_versions_host: bool,
) -> Result<GithubRelease> {
let key = format!("{api_url}-{repo}-{tag}-versions-host-{use_versions_host}").to_kebab_case();
let cache = get_release_cache(&key).await;
let cache = cache.get(&key).unwrap();
cache
.get_or_try_init_async_if(
async || get_release_(api_url, repo, tag).await,
async || get_release_with_options(api_url, repo, tag, use_versions_host).await,
should_cache_release,
)
.await
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -357,7 +362,17 @@ fn pick_best_build_revision(releases: Vec<GithubRelease>, version: &str) -> Opti
}

async fn get_release_(api_url: &str, repo: &str, tag: &str) -> Result<GithubRelease> {
if is_public_github_api_base(api_url)
get_release_with_options(api_url, repo, tag, true).await
}

async fn get_release_with_options(
api_url: &str,
repo: &str,
tag: &str,
use_versions_host: bool,
) -> Result<GithubRelease> {
if use_versions_host
&& is_public_github_api_base(api_url)
&& let Ok(Some(release)) = crate::versions_host::github_release(repo, tag).await
{
trace!("got GitHub release {repo}@{tag} from mise-versions");
Expand Down Expand Up @@ -914,7 +929,7 @@ something_else = "value"
let repo = "owner/empty-assets-cache-test";
let tag = "v1.0.0";
let path = format!("/repos/{repo}/releases/tags/{tag}");
let key = format!("{}-{repo}-{tag}", server.url()).to_kebab_case();
let key = format!("{}-{repo}-{tag}-versions-host-true", server.url()).to_kebab_case();

let cached_empty_release = make_release(tag);
{
Expand All @@ -932,7 +947,9 @@ something_else = "value"
.create_async()
.await;

let release = get_release_for_url(&server.url(), repo, tag).await.unwrap();
let release = get_release_for_url_with_versions_host(&server.url(), repo, tag, true)
.await
.unwrap();
assert!(release.assets.is_empty());
empty_mock.assert_async().await;
empty_mock.remove_async().await;
Expand All @@ -950,11 +967,15 @@ something_else = "value"
.create_async()
.await;

let release = get_release_for_url(&server.url(), repo, tag).await.unwrap();
let release = get_release_for_url_with_versions_host(&server.url(), repo, tag, true)
.await
.unwrap();
assert_eq!(release.assets.len(), 1);
assert_eq!(release.assets[0].name, "tool-v1.0.0-linux-x86_64.tar.gz");

let release = get_release_for_url(&server.url(), repo, tag).await.unwrap();
let release = get_release_for_url_with_versions_host(&server.url(), repo, tag, true)
.await
.unwrap();
assert_eq!(release.assets.len(), 1);
mock.assert_async().await;
}
Expand Down
Loading