* `fj repo branches`, `repo topics`, `repo edit`, `repo fork`, `repo sync`, `repo archive`, `repo unarchive`, `repo mirror-sync` previously took only a positional `repo` argument and rejected `-R/--repo`. Now they accept both, with `-R` winning when both are given. * Forgejo returns `null` for `labels`/`assignees` on issues and PRs when empty. The Issue/Pull structs hit `expected a sequence` on every issue create. Added a `deserialize_null_to_default` helper on the affected fields so null is now coerced to an empty Vec. * `get_page` similarly bailed when a list endpoint returned a bare `null` body. Now treats null and empty body as `[]`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1 KiB
Rust
50 lines
1 KiB
Rust
pub mod hook;
|
|
pub mod issue;
|
|
pub(crate) mod serde_util;
|
|
pub mod label;
|
|
pub mod notification;
|
|
pub mod org;
|
|
pub mod protect;
|
|
pub mod pull;
|
|
pub mod release;
|
|
pub mod repo;
|
|
pub mod search;
|
|
pub mod user;
|
|
pub mod workflow;
|
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
/// Split an `owner/name` slug. Returns a helpful error if the form is wrong.
|
|
pub fn split_repo(repo: &str) -> Result<(&str, &str)> {
|
|
repo.split_once('/')
|
|
.filter(|(o, n)| !o.is_empty() && !n.is_empty())
|
|
.ok_or_else(|| anyhow!("expected '<owner>/<name>', got '{repo}'"))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn parses_normal_slug() {
|
|
let (o, n) = split_repo("rasterstate/fj").unwrap();
|
|
assert_eq!(o, "rasterstate");
|
|
assert_eq!(n, "fj");
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_missing_slash() {
|
|
assert!(split_repo("fj").is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_empty_owner() {
|
|
assert!(split_repo("/fj").is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_empty_name() {
|
|
assert!(split_repo("rasterstate/").is_err());
|
|
}
|
|
}
|