Skip to content

Commit

Permalink
new: Support monorepos for github:// locators. (#555)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Jul 26, 2024
1 parent 9789648 commit 4bcf4c0
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 304 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Added a new setting to `.prototools`, `settings.builtin-plugins`, that can be used to disable all built-in plugins, or only allow a few select plugins.
- Supports a boolean or list of plugin names.
- All are enabled by default for backwards compatibility.
- Updated `github://` plugin locators to support monorepos. Append the project name (that tags are prefixed with) to the path: `github://moonrepo/tools/node_tool`
- Merged `proto use` and `proto install` commands. If no arguments are provided to `proto install`, it will install all configured tools.

## 0.38.4
Expand Down
2 changes: 1 addition & 1 deletion crates/core/tests/proto_config_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ bar = "https://moonrepo.dev/path/file.wasm"
(
Id::raw("foo"),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "foo_plugin".into(),
repo_slug: "moonrepo/foo".into(),
tag: None,
project_name: None
}))
),
])
Expand Down
46 changes: 14 additions & 32 deletions crates/warpgate-api/src/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,14 @@ use std::str::FromStr;
/// A GitHub release locator.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct GitHubLocator {
/// Name of asset without extension.
/// Defaults to `<repo>_plugin`.
pub file_prefix: String,

/// Organization and repository slug: `owner/repo`.
pub repo_slug: String,

/// Release tag to use. Defaults to `latest`.
/// Explicit release tag to use. Defaults to `latest`.
pub tag: Option<String>,
}

impl GitHubLocator {
pub fn extract_prefix_from_slug(slug: &str) -> &str {
slug.split('/').next().expect("Expected an owner scope!")
}

pub fn extract_suffix_from_slug(slug: &str) -> &str {
slug.split('/').nth(1).expect("Expected a repository name!")
}
/// Project name to match tags against. Primarily used in monorepos.
pub project_name: Option<String>,
}

/// Errors during plugin locator parsing.
Expand Down Expand Up @@ -61,6 +50,7 @@ pub enum PluginLocator {

/// github://owner/repo
/// github://owner/repo@tag
/// github://owner/repo/project
GitHub(Box<GitHubLocator>),

/// https://url/to/file.wasm
Expand All @@ -70,18 +60,6 @@ pub enum PluginLocator {
},
}

impl PluginLocator {
pub fn create_wasm_file_prefix(name: &str) -> String {
let mut name = name.to_lowercase().replace('-', "_");

if !name.ends_with("_plugin") {
name.push_str("_plugin");
}

name
}
}

#[cfg(feature = "schematic")]
impl schematic::Schematic for PluginLocator {
fn schema_name() -> Option<String> {
Expand All @@ -101,8 +79,13 @@ impl Display for PluginLocator {
PluginLocator::Url { url } => write!(f, "{}", url),
PluginLocator::GitHub(github) => write!(
f,
"github://{}{}",
"github://{}{}{}",
github.repo_slug,
github
.project_name
.as_deref()
.map(|n| format!("/{n}"))
.unwrap_or_default(),
github
.tag
.as_deref()
Expand Down Expand Up @@ -173,12 +156,11 @@ impl TryFrom<String> for PluginLocator {
}

let mut parts = query.split('/');
let org = parts.next().unwrap().to_owned();
let repo = parts.next().unwrap().to_owned();
let file = parts.next().map(|f| f.to_owned());
let org = parts.next().unwrap_or_default().to_owned();
let repo = parts.next().unwrap_or_default().to_owned();
let prefix = parts.next().map(|f| f.to_owned());

github.file_prefix =
file.unwrap_or_else(|| PluginLocator::create_wasm_file_prefix(&repo));
github.project_name = prefix;
github.repo_slug = format!("{org}/{repo}");

Ok(PluginLocator::GitHub(Box::new(github)))
Expand Down
36 changes: 28 additions & 8 deletions crates/warpgate-api/tests/locator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,43 @@ mod locator {

assert_eq!(
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "proto_plugin".into(),
repo_slug: "moonrepo/proto".into(),
tag: None,
project_name: None,
}))
.to_string(),
"github://moonrepo/proto"
);

assert_eq!(
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "proto_plugin".into(),
repo_slug: "moonrepo/proto".into(),
tag: None,
project_name: Some("tool".into()),
}))
.to_string(),
"github://moonrepo/proto/tool"
);

assert_eq!(
PluginLocator::GitHub(Box::new(GitHubLocator {
repo_slug: "moonrepo/proto".into(),
tag: Some("latest".into()),
project_name: None,
}))
.to_string(),
"github://moonrepo/proto@latest"
);

assert_eq!(
PluginLocator::GitHub(Box::new(GitHubLocator {
repo_slug: "moonrepo/proto".into(),
tag: Some("latest".into()),
project_name: Some("tool".into()),
}))
.to_string(),
"github://moonrepo/proto/tool@latest"
);
}

#[test]
Expand Down Expand Up @@ -150,9 +170,9 @@ mod locator {
assert_eq!(
PluginLocator::try_from("github:moonrepo/bun".to_string()).unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_plugin".into(),
repo_slug: "moonrepo/bun".into(),
tag: None,
project_name: None,
}))
);
}
Expand All @@ -162,9 +182,9 @@ mod locator {
assert_eq!(
PluginLocator::try_from("github://moonrepo/bun".to_string()).unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_plugin".into(),
repo_slug: "moonrepo/bun".into(),
tag: None,
project_name: None,
}))
);
}
Expand All @@ -174,9 +194,9 @@ mod locator {
assert_eq!(
PluginLocator::try_from("github://moonrepo/tools/bun_tool".to_string()).unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_tool".into(),
repo_slug: "moonrepo/tools".into(),
tag: None,
project_name: Some("bun_tool".into()),
}))
);
}
Expand All @@ -186,9 +206,9 @@ mod locator {
assert_eq!(
PluginLocator::try_from("github://moonrepo/bun-plugin@latest".to_string()).unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_plugin".into(),
repo_slug: "moonrepo/bun-plugin".into(),
tag: Some("latest".into()),
project_name: None,
}))
);
}
Expand All @@ -198,9 +218,9 @@ mod locator {
assert_eq!(
PluginLocator::try_from("github://moonrepo/[email protected]".to_string()).unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_plugin".into(),
repo_slug: "moonrepo/bun_plugin".into(),
tag: Some("v1.2.3".into()),
project_name: None,
}))
);
}
Expand All @@ -211,9 +231,9 @@ mod locator {
PluginLocator::try_from("github://moonrepo/tools/[email protected]".to_string())
.unwrap(),
PluginLocator::GitHub(Box::new(GitHubLocator {
file_prefix: "bun_tool".into(),
repo_slug: "moonrepo/tools".into(),
tag: Some("v1.2.3".into()),
project_name: Some("bun_tool".into()),
}))
);
}
Expand Down
9 changes: 5 additions & 4 deletions crates/warpgate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,17 @@ Download an asset from a GitHub release. This approach communicates with the Git
Defining a `GITHUB_TOKEN` environment variable is recommended to avoid rate limiting.

```rust
// github:org/repo
// github:org/[email protected]
// github://org/repo
// github://org/[email protected]
// github://org/repo/project
PluginLocator::GitHub(GitHubLocator{
file_prefix: "file_prefix".into(),
repo_slug: "org/repo".into(),
project_name: None,
tag: Some("v1.2.3".into()), // Latest if `None`
})
```

> The `file_prefix` cannot be configured with the string format, and defaults to the repository name in snake_case, suffixed with `_plugin`.
> The `project_name` field exists to support monorepos. When defined, it will look for a tag/release that starts with the project name. For example, if the project name was `example_plugin`, it will match `example_plugin-v1.2.3` or `[email protected]` tags.
## Extism plugin containers

Expand Down
5 changes: 5 additions & 0 deletions crates/warpgate/src/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ pub struct GitHubApiAsset {
pub name: String,
}

#[derive(Debug, Deserialize)]
pub struct GitHubApiTag {
pub name: String,
}

#[derive(Default, Deserialize)]
#[serde(default)]
pub struct GitHubApiRelease {
Expand Down
8 changes: 8 additions & 0 deletions crates/warpgate/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ pub enum WarpgateError {
)]
SourceFileMissing { id: Id, path: PathBuf },

#[diagnostic(code(plugin::github::asset_missing))]
#[error(
"Cannot download {} plugin from GitHub ({}), no tag found or provided.",
.id.style(Style::Id),
.repo_slug.style(Style::Id),
)]
GitHubTagMissing { id: Id, repo_slug: String },

#[diagnostic(code(plugin::github::asset_missing))]
#[error(
"Cannot download {} plugin from GitHub ({}), no applicable asset found for release {}.",
Expand Down
Loading

0 comments on commit 4bcf4c0

Please sign in to comment.