diff options
| author | seth <[email protected]> | 2024-10-10 07:26:29 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-10-10 07:26:29 -0400 |
| commit | c61b701095a1f6b52777d317275f34687e57ee3e (patch) | |
| tree | e5b1e80fa8040b593aeebb9daf83bcc9d78c6e81 /crates | |
| parent | 4e1fab6ff1d17a0fff50e1a87af8c0bbe8c075f9 (diff) | |
rise once again my glorious creation (#51)
* git-tracker: update tips after fetch + cleanup
* nix: use nix-filter
* ci: cleanup
* crates: update
* git-tracker: don't spam log while transferring
* nix: fix static package eval
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/discord-bot/Cargo.toml | 10 | ||||
| -rw-r--r-- | crates/discord-bot/src/commands/track.rs | 29 | ||||
| -rw-r--r-- | crates/discord-bot/src/config.rs | 51 | ||||
| -rw-r--r-- | crates/discord-bot/src/consts.rs | 5 | ||||
| -rw-r--r-- | crates/discord-bot/src/jobs.rs | 22 | ||||
| -rw-r--r-- | crates/discord-bot/src/lib.rs | 3 | ||||
| -rw-r--r-- | crates/git-tracker/Cargo.toml | 4 | ||||
| -rw-r--r-- | crates/git-tracker/src/lib.rs | 239 | ||||
| -rw-r--r-- | crates/git-tracker/src/managed_repository.rs | 95 | ||||
| -rw-r--r-- | crates/git-tracker/src/tracker.rs | 109 | ||||
| -rw-r--r-- | crates/nixpkgs-tracker-http/Cargo.toml | 4 |
11 files changed, 270 insertions, 301 deletions
diff --git a/crates/discord-bot/Cargo.toml b/crates/discord-bot/Cargo.toml index e45d30e..4eff6ac 100644 --- a/crates/discord-bot/Cargo.toml +++ b/crates/discord-bot/Cargo.toml @@ -14,14 +14,14 @@ name = "nixpkgs-tracker-bot" path = "src/main.rs" [dependencies] -dotenvy = "0.15.7" -env_logger = "0.11.5" -eyre = "0.6.12" +dotenvy = "0.15" +env_logger = "0.11" +eyre = "0.6" git-tracker.workspace = true log.workspace = true nixpkgs-tracker-http.workspace = true -serenity = { version = "0.12.2", features = ["unstable_discord_api"] } -tokio = { version = "1.40.0", features = [ +serenity = { version = "0.12", features = ["unstable_discord_api"] } +tokio = { version = "1.40", features = [ "macros", "rt-multi-thread", "signal" diff --git a/crates/discord-bot/src/commands/track.rs b/crates/discord-bot/src/commands/track.rs index f071ebf..0f0e0be 100644 --- a/crates/discord-bot/src/commands/track.rs +++ b/crates/discord-bot/src/commands/track.rs @@ -1,4 +1,4 @@ -use crate::{config::Config, consts::NIXPKGS_REMOTE, http::GitHubClientExt}; +use crate::{config::Config, http::GitHubClientExt}; use std::sync::Arc; @@ -70,25 +70,18 @@ where return Ok(()); }; - let status_results = git_tracker::collect_statuses_in( - &config.nixpkgs_path, - &commit_sha, - &config.nixpkgs_branches, - )?; - - // find branches containing our PR and trim the remote ref prefix - let found_branches: Vec<String> = status_results + let repository = config.repository(); + let branch_results = repository.branches_contain_sha(config.nixpkgs_branches(), &commit_sha)?; + let fields: Vec<_> = branch_results .iter() - .filter(|&(_, has_pr)| *has_pr) - .map(|(branch_name, _)| { - // remove the ref prefix that we add in our Config struct - let start_pos = format!("{NIXPKGS_REMOTE}/").len(); - branch_name[start_pos..].to_string() + .map(|(name, has_commit)| { + let emoji = if *has_commit { "✅" } else { "❌" }; + (*name, emoji, true) }) .collect(); // if we didn't find any, bail - if found_branches.is_empty() { + if fields.is_empty() { let response = CreateInteractionResponseFollowup::new() .content("This PR has been merged...but I can't seem to find it anywhere. I might not be tracking it's base branch"); command.create_followup(&ctx, response).await?; @@ -100,11 +93,7 @@ where .title(format!("Nixpkgs PR #{} Status", pull_request.number)) .url(&pull_request.html_url) .description(&pull_request.title) - .fields( - found_branches - .iter() - .map(|branch_name| (branch_name, "✅", true)), - ); + .fields(fields); if let Some(merged_at) = pull_request.merged_at { if let Ok(timestamp) = Timestamp::parse(&merged_at) { diff --git a/crates/discord-bot/src/config.rs b/crates/discord-bot/src/config.rs index 5076eb9..afc7845 100644 --- a/crates/discord-bot/src/config.rs +++ b/crates/discord-bot/src/config.rs @@ -1,25 +1,21 @@ -use crate::consts::NIXPKGS_REMOTE; +use git_tracker::TrackedRepository; -use std::env; +use std::{env, path::PathBuf, sync::Arc}; + +const DEFAULT_NIXPKGS_URL: &str = "https://github.com/NixOS/nixpkgs"; + +const DEFAULT_NIXPKGS_REMOTE: &str = "origin"; /// The Discord client's configuration #[derive(Clone, Debug)] pub struct Config { - /// Path to clone a new or use an existing nixpkgs repository - pub nixpkgs_path: String, - // A comma separated list of nixpkgs branch to track commits for - pub nixpkgs_branches: Vec<String>, + /// Comma separated list of nixpkgs branch to track commits for + nixpkgs_branches: Vec<String>, + /// Repository tracker + repository: Arc<TrackedRepository>, } impl Config { - /// Take in a comma separated list and split it into a [`Vec<String>`] - fn split_string_list(branches: &str) -> Vec<String> { - branches - .split(',') - .map(|branch| format!("{NIXPKGS_REMOTE}/{}", branch.trim())) - .collect() - } - /// Create a new instance of [`Config`] based on variables from the environment /// /// # Errors @@ -27,12 +23,33 @@ impl Config { /// Will return [`Err`] if a variable is not found pub fn from_env() -> Result<Self, env::VarError> { let nixpkgs_path = env::var("BOT_NIXPKGS_PATH")?; - let nixpkgs_branches_raw = env::var("BOT_NIXPKGS_BRANCHES")?; - let nixpkgs_branches = Self::split_string_list(&nixpkgs_branches_raw); + + let nixpkgs_branches = env::var("BOT_NIXPKGS_BRANCHES")? + .split(',') + .map(ToString::to_string) + .collect(); + + let nixpkgs_remote = + env::var("BOT_NIXPKGS_REMOTE").unwrap_or(DEFAULT_NIXPKGS_REMOTE.to_string()); + let nixpkgs_url = env::var("BOT_NIXPKGS_URL").unwrap_or(DEFAULT_NIXPKGS_URL.to_string()); + + let repository = TrackedRepository::new( + PathBuf::from(nixpkgs_path.clone()), + nixpkgs_url, + nixpkgs_remote, + ); Ok(Self { - nixpkgs_path, nixpkgs_branches, + repository: Arc::new(repository), }) } + + pub fn repository(&self) -> &TrackedRepository { + &self.repository + } + + pub fn nixpkgs_branches(&self) -> &Vec<String> { + &self.nixpkgs_branches + } } diff --git a/crates/discord-bot/src/consts.rs b/crates/discord-bot/src/consts.rs deleted file mode 100644 index 9396da0..0000000 --- a/crates/discord-bot/src/consts.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// URL to the nixpkgs repository -pub const NIXPKGS_URL: &str = "https://github.com/NixOS/nixpkgs"; - -/// The Git remote for upstream nixpkgs in our local copy -pub const NIXPKGS_REMOTE: &str = "origin"; diff --git a/crates/discord-bot/src/jobs.rs b/crates/discord-bot/src/jobs.rs index 40d34cc..f35c471 100644 --- a/crates/discord-bot/src/jobs.rs +++ b/crates/discord-bot/src/jobs.rs @@ -1,9 +1,8 @@ -use crate::{config::Config, consts::NIXPKGS_REMOTE, consts::NIXPKGS_URL}; +use crate::config::Config; -use std::{path::Path, time::Duration}; +use std::time::Duration; use eyre::Result; -use git_tracker::ManagedRepository; use log::error; const TTL_SECS: u64 = 60 * 5; // 5 minutes @@ -13,20 +12,19 @@ const TTL_SECS: u64 = 60 * 5; // 5 minutes /// # Errors /// /// Will return [`Err`] if any jobs fail -pub fn dispatch(config: Config) -> Result<()> { - let managed_repository = ManagedRepository { - path: Path::new(&config.nixpkgs_path).to_path_buf(), - tracked_branches: config.nixpkgs_branches, - upstream_remote_url: NIXPKGS_URL.to_string(), - upstream_remote_name: NIXPKGS_REMOTE.to_string(), - }; +pub fn dispatch(config: &Config) -> Result<()> { + let repository = config.repository(); + if repository.open().is_err() { + repository.clone_repository()?; + } + repository.fetch()?; - managed_repository.fetch_or_update()?; + let repository_clone = repository.clone(); tokio::spawn(async move { loop { tokio::time::sleep(Duration::from_secs(TTL_SECS)).await; - if let Err(why) = managed_repository.fetch_or_update() { + if let Err(why) = repository_clone.fetch() { error!("Could not fetch or update repository!\n{why:?}"); }; } diff --git a/crates/discord-bot/src/lib.rs b/crates/discord-bot/src/lib.rs index 7ac2e98..3248db5 100644 --- a/crates/discord-bot/src/lib.rs +++ b/crates/discord-bot/src/lib.rs @@ -6,7 +6,6 @@ use serenity::prelude::{Client, GatewayIntents, TypeMapKey}; mod commands; mod config; -mod consts; mod handler; mod jobs; @@ -76,7 +75,7 @@ pub async fn client() -> Result<Client> { }); // run our jobs - jobs::dispatch(config)?; + jobs::dispatch(&config)?; Ok(client) } diff --git a/crates/git-tracker/Cargo.toml b/crates/git-tracker/Cargo.toml index 3027769..14af5d0 100644 --- a/crates/git-tracker/Cargo.toml +++ b/crates/git-tracker/Cargo.toml @@ -9,9 +9,9 @@ repository.workspace = true publish = false [dependencies] -git2 = { version = "0.19.0", default-features = false, features = ["https"] } +git2 = { version = "0.19", default-features = false, features = ["https"] } log.workspace = true -thiserror = "1.0.64" +thiserror = "1.0" [lints] workspace = true diff --git a/crates/git-tracker/src/lib.rs b/crates/git-tracker/src/lib.rs index 0bf17dc..e2feb32 100644 --- a/crates/git-tracker/src/lib.rs +++ b/crates/git-tracker/src/lib.rs @@ -1,35 +1,210 @@ -//! A library that helps you track commits and branches in a Git repository -use log::trace; - -mod managed_repository; -mod tracker; -pub use managed_repository::ManagedRepository; -pub use tracker::Tracker; - -/// Collect the status of the commit SHA [`commit_sha`] in each of the nixpkgs -/// branches in [`branches`], using the repository at path [`repository_path`] -/// -/// NOTE: `branches` should contain the full ref (i.e., `origin/main`) -/// -/// # Errors -/// -/// Will return [`Err`] if we can't start tracking a repository at the given path, -/// or if we can't determine if the branch has given commit -pub fn collect_statuses_in( - repository_path: &str, - commit_sha: &str, - branches: &Vec<String>, -) -> Result<Vec<(String, bool)>, tracker::Error> { - // start tracking nixpkgs - let tracker = Tracker::from_path(repository_path)?; - - // check to see what branches it's in - let mut status_results = Vec::new(); - for branch_name in branches { - trace!("Checking for commit in {branch_name}"); - let has_pr = tracker.branch_contains_sha(branch_name, commit_sha)?; - status_results.push((branch_name.to_string(), has_pr)); +//! Library for helping you track commits and branches in a Git repository +use std::path::PathBuf; + +use git2::{ + BranchType, FetchOptions, FetchPrune, Oid, Reference, RemoteCallbacks, RemoteUpdateFlags, + Repository, +}; +use log::{debug, info, trace}; + +/// Used when logging Git transfer progress +const INCREMENT_TO_LOG: i32 = 5; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("libgit2 error")] + Git(#[from] git2::Error), + #[error("i/o error")] + IOError(#[from] std::io::Error), +} + +/// Helper struct for tracking Git objects +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct TrackedRepository { + /// Path to repository + path: PathBuf, + /// URL of the Git remote + remote_url: String, + /// Name of the remote referring to `remote_url` + remote_name: String, +} + +impl TrackedRepository { + #[must_use] + pub fn new(path: PathBuf, remote_url: String, remote_name: String) -> Self { + Self { + path, + remote_url, + remote_name, + } + } + + /// Open a [`Repository`] + /// + /// # Errors + /// + /// Will return [`Err`] if the repository cannot be opened + pub fn open(&self) -> Result<Repository, Error> { + trace!("Opening repository at {}", self.path.display()); + Ok(Repository::open(&self.path)?) + } + + /// Clone a (small) fresh copy of your repository + /// + /// # Errors + /// + /// Will return [`Err`] if the path, repository, or remote cannot be created + pub fn clone_repository(&self) -> Result<(), Error> { + // Setup a bare repository to save space + info!("Creating repository at {}", self.path.display()); + std::fs::create_dir_all(&self.path)?; + let repository = Repository::init_bare(&self.path)?; + + debug!("Adding remote {} for {}", self.remote_name, self.remote_url,); + repository.remote(&self.remote_name, &self.remote_url)?; + self.fetch()?; + + Ok(()) + } + + #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] + fn fetch_options<'a>() -> FetchOptions<'a> { + let mut rc = RemoteCallbacks::new(); + + // Log transfer progress + let mut current_percentage = 1; + rc.transfer_progress(move |stats| { + if stats.received_objects() == stats.total_objects() { + // HACK: Avoid dividing by zero + // I have no idea how this can ever be zero but ok + let total_deltas = stats.total_deltas(); + if total_deltas == 0 { + return true; + } + + let percentage = + (stats.indexed_deltas() as f32 / stats.total_deltas() as f32 * 100.0) as i32; + if percentage != current_percentage && percentage % INCREMENT_TO_LOG == 0 { + info!( + "Resolving deltas {}/{}\r", + stats.indexed_deltas(), + stats.total_deltas() + ); + current_percentage = percentage; + } + } else if stats.total_objects() > 0 { + let percentage = + (stats.received_objects() as f32 / stats.total_objects() as f32 * 100.0) as i32; + if percentage != current_percentage && percentage % INCREMENT_TO_LOG == 0 { + info!( + "Received {}/{} objects ({}) in {} bytes\r", + stats.received_objects(), + stats.total_objects(), + stats.indexed_objects(), + stats.received_bytes() + ); + current_percentage = percentage; + } + } + + true + }); + + // Log ref updates + rc.update_tips(|refname, orig_oid, new_oid| { + if orig_oid.is_zero() { + info!("[new] {:20} {}", new_oid, refname); + } else { + info!("[updated] {:10}..{:10} {}", orig_oid, new_oid, refname); + } + true + }); + + let mut fetch_options = FetchOptions::new(); + // Make sure we prune on fetch + fetch_options.prune(FetchPrune::On).remote_callbacks(rc); + + fetch_options + } + + /// Fetch the tracked remote + /// + /// # Errors + /// + /// Will return [`Err`] if the repository cannot be opened, the remote cannot be found, the + /// refs cannot be fetched, or the tips of the refs cannot be updated + pub fn fetch(&self) -> Result<(), Error> { + let repository = self.open()?; + + let mut remote = repository.find_remote(&self.remote_name)?; + + info!("Fetching repository"); + remote.download(&[] as &[&str], Some(&mut Self::fetch_options()))?; + remote.disconnect()?; + + debug!("Updating tips"); + remote.update_tips( + None, + RemoteUpdateFlags::UPDATE_FETCHHEAD, + git2::AutotagOption::None, + None, + )?; + + Ok(()) } - Ok(status_results) + /// Check if a [`Reference`] contains a given Git object + /// + /// # Errors + /// + /// Will return [`Err`] if the repository cannot be opened, HEAD cannot be resolved, or the + /// relation between commits cannot be resolved + pub fn ref_contains_object(&self, reference: &Reference, commit: Oid) -> Result<bool, Error> { + trace!( + "Checking for commit {commit} in {}", + reference.name().unwrap_or("<branch>") + ); + let repository = self.open()?; + let head = reference.peel_to_commit()?; + + // NOTE: we have to check this as `Repository::graph_descendant_of()` (like the name says) + // only finds *descendants* of it's parent commit, and will not tell us if the parent commit + // *is* the child commit. i have no idea why i didn't think of this, but that's why this + // comment is here now + if head.id() == commit { + return Ok(true); + } + + let has_commit = repository.graph_descendant_of(head.id(), commit)?; + + Ok(has_commit) + } + + /// Check if multiple [`Reference`]s contain a commit SHA + /// + /// # Errors + /// + /// Will return [`Err`] if an [`Oid`] could not be resolved from the commit SHA + /// or when it can't be determined if a reference contains a commit + pub fn branches_contain_sha<'a>( + &self, + branch_names: impl IntoIterator<Item = &'a String>, + commit_sha: &str, + ) -> Result<Vec<(&'a String, bool)>, Error> { + let repository = self.open()?; + let commit = Oid::from_str(commit_sha)?; + + let mut results = vec![]; + for branch_name in branch_names { + let branch = repository.find_branch( + &format!("{}/{branch_name}", self.remote_name), + BranchType::Remote, + )?; + + let has_commit = self.ref_contains_object(&branch.into_reference(), commit)?; + results.push((branch_name, has_commit)); + } + + Ok(results) + } } diff --git a/crates/git-tracker/src/managed_repository.rs b/crates/git-tracker/src/managed_repository.rs deleted file mode 100644 index 0a41bd0..0000000 --- a/crates/git-tracker/src/managed_repository.rs +++ /dev/null @@ -1,95 +0,0 @@ -use git2::{AutotagOption, FetchOptions, RemoteCallbacks, RemoteUpdateFlags, Repository}; -use log::{debug, info, trace, warn}; -use std::{io::Write, path::PathBuf}; - -// much of this is shamelessly lifted from -// https://github.com/rust-lang/git2-rs/blob/9a5c9706ff578c936be644dd1e8fe155bdc4d129/examples/pull.rs - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("libgit2 error")] - Git(#[from] git2::Error), -} - -pub struct ManagedRepository { - pub path: PathBuf, - pub tracked_branches: Vec<String>, - pub upstream_remote_url: String, - pub upstream_remote_name: String, -} - -impl ManagedRepository { - /// basic set of options for fetching from remotes - fn fetch_options<'a>() -> FetchOptions<'a> { - let mut remote_callbacks = RemoteCallbacks::new(); - remote_callbacks.transfer_progress(|progress| { - if progress.received_objects() == progress.total_objects() { - trace!( - "Resolving deltas {}/{}\r", - progress.indexed_deltas(), - progress.total_deltas() - ); - } else { - trace!( - "Received {}/{} objects ({}) in {} bytes\r", - progress.received_objects(), - progress.total_objects(), - progress.indexed_objects(), - progress.received_bytes() - ); - } - std::io::stdout().flush().ok(); - true - }); - - let mut fetch_opts = FetchOptions::new(); - fetch_opts.remote_callbacks(remote_callbacks); - - fetch_opts - } - - /// Update the given branches in the [`repository`] using the nixpkgs remote - fn update_branches_in(&self, repository: &Repository) -> Result<(), Error> { - let mut remote = repository.find_remote(&self.upstream_remote_name)?; - // download all the refs - remote.download(&self.tracked_branches, Some(&mut Self::fetch_options()))?; - remote.disconnect()?; - // and (hopefully) update what they refer to for later - remote.update_tips( - None, - RemoteUpdateFlags::UPDATE_FETCHHEAD, - AutotagOption::Auto, - None, - )?; - - Ok(()) - } - - /// Fetch the repository or update it if it exists - /// - /// # Errors - /// Will return [`Err`] if the repository cannot be opened, cloned, or updated - pub fn fetch_or_update(&self) -> Result<(), Error> { - // Open our repository or clone it if it doesn't exist - let repository = if self.path.exists() { - Repository::open(self.path.as_path())? - } else { - warn!( - "Couldn't find repository at {}! Cloning a fresh one from {}", - self.path.display(), - self.upstream_remote_url - ); - Repository::clone(&self.upstream_remote_url, self.path.as_path())?; - info!("Finished cloning to {}", self.path.display()); - - // bail early as we already have a fresh copy - return Ok(()); - }; - - debug!("Updating repository at {}", self.path.display()); - self.update_branches_in(&repository)?; - debug!("Finished updating!"); - - Ok(()) - } -} diff --git a/crates/git-tracker/src/tracker.rs b/crates/git-tracker/src/tracker.rs deleted file mode 100644 index e6a3f54..0000000 --- a/crates/git-tracker/src/tracker.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::path::Path; - -use git2::{Branch, BranchType, Commit, ErrorCode, Oid, Reference, Repository}; - -/// Helper struct for tracking Git objects -pub struct Tracker { - repository: Repository, -} - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("libgit2 error")] - Git(#[from] git2::Error), - #[error("Repository path not found at `{0}`")] - RepositoryPathNotFound(String), -} - -impl Tracker { - /// Create a new [`Tracker`] using the repository at [`path`] - /// - /// # Errors - /// - /// Will return [`Err`] if the repository can not be opened - pub fn from_path(path: &str) -> Result<Self, Error> { - let repository_path = Path::new(path); - if repository_path.exists() { - let repository = Repository::open(repository_path)?; - Ok(Self { repository }) - } else { - Err(Error::RepositoryPathNotFound(path.to_string())) - } - } - - /// Finds a branch of name [`name`] - /// - /// # Errors - /// - /// Will return [`Err`] if the branch cannot be found locally - pub fn branch_by_name(&self, name: &str) -> Result<Branch, Error> { - Ok(self.repository.find_branch(name, BranchType::Remote)?) - } - - /// Finds a commit with a SHA match [`sha`] - /// - /// # Errors - /// - /// Will return [`Err`] if [`sha`] cannot be converted an [`Oid`] or - /// a commit matching it cannot be found - pub fn commit_by_sha(&self, sha: &str) -> Result<Commit, Error> { - let oid = Oid::from_str(sha)?; - let commit = self.repository.find_commit(oid)?; - - Ok(commit) - } - - /// Check if [`Reference`] [`ref`] contains [`Commit`] [`commit`] - /// - /// # Errors - /// - /// Will return [`Err`] if the reference cannot be resolved to a commit or the descendants - /// of the reference cannot be resolved - pub fn ref_contains_commit( - &self, - reference: &Reference, - commit: &Commit, - ) -> Result<bool, Error> { - let head = reference.peel_to_commit()?; - - // NOTE: we have to check this as `Repository::graph_descendant_of()` (like the name says) - // only finds *descendants* of it's parent commit, and will not tell us if the parent commit - // *is* the child commit. i have no idea why i didn't think of this, but that's why this - // comment is here now - let is_head = head.id() == commit.id(); - - let has_commit = self - .repository - .graph_descendant_of(head.id(), commit.id())?; - - Ok(is_head || has_commit) - } - - /// Check if a [`Branch`] named [`branch_name`] has a commit with the SHA [`commit_sha`] - /// - /// # Errors - /// - /// Will return [`Err`] if the commit SHA cannot be resolved to an object id, the branch name cannot - /// be resolved to a branch, or the descendants of the resolved branch cannot be resolved - pub fn branch_contains_sha(&self, branch_name: &str, commit_sha: &str) -> Result<bool, Error> { - let commit = match self.commit_by_sha(commit_sha) { - Ok(commit) => commit, - Err(why) => { - // NOTE: we assume commits not found are just not in the branch *yet*, not an error - // this is because github decides to report merge commit shas for unmerged PRs...yeah - if let Error::Git(git_error) = &why { - if git_error.code() == ErrorCode::NotFound { - return Ok(false); - } - } - - return Err(why); - } - }; - - let branch = self.branch_by_name(branch_name)?; - let has_pr = self.ref_contains_commit(&branch.into_reference(), &commit)?; - - Ok(has_pr) - } -} diff --git a/crates/nixpkgs-tracker-http/Cargo.toml b/crates/nixpkgs-tracker-http/Cargo.toml index ca95804..c4bcf46 100644 --- a/crates/nixpkgs-tracker-http/Cargo.toml +++ b/crates/nixpkgs-tracker-http/Cargo.toml @@ -10,13 +10,13 @@ publish = false [dependencies] log.workspace = true -reqwest = { version = "0.12.8", default-features = false, features = [ +reqwest = { version = "0.12", default-features = false, features = [ "charset", "http2", "rustls-tls", "json" ] } -serde = { version = "1.0.210", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } [lints] workspace = true |
