summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseth <[email protected]>2024-08-16 22:14:16 -0400
committerGitHub <[email protected]>2024-08-17 02:14:16 +0000
commitbbc00edc6508ea1910c4d9e6a272f7859900950d (patch)
tree538fe23940cb6bca8afa48059e502bfa7d5608cd
parent66ea6f8c225cc2273cfbfb1b948604c170a78e8c (diff)
end of summer refactor (#31)
* crates: `bot-*` -> `discord-bot` I didn't really need all these crates to be split :/ * discord-bot: revamp http impl also handles the new errors reported by teawieAPI * crates: split http backend this can be reused easily * git-tracker: short-circuit boolean logic We don't need to check if the commit is a descendant of the HEAD of the branch if it *is* the HEAD * nix: fenix -> nixpkgs * treefmt: add actionlint * nix: use docker arch names for containers * ci: use actions-rust-lang actions * nix: drop ci dev shell * git-tracker: init ManagedRepository this logic can be shared * ci: use nix for clippy scan * discord-bot: better handle unmerged PRs * ci: fix treefmt check * nix: fix clippy check * .env.template: update crate names * git-tracker: use remote name for remote name i was half asleep * discord-bot: handle merged PRs that aren't found in any tracked branches * git-tracker: make collect_statuses_in() return a Vec * discord-bot: add more PR info with response fixes #18
-rw-r--r--.env.template4
-rw-r--r--.github/workflows/ci.yaml43
-rw-r--r--.github/workflows/clippy.yaml40
-rw-r--r--.github/workflows/docker.yaml16
-rw-r--r--Cargo.lock113
-rw-r--r--Cargo.toml45
-rw-r--r--crates/bot-client/Cargo.toml32
-rw-r--r--crates/bot-commands/Cargo.toml34
-rw-r--r--crates/bot-commands/src/track.rs121
-rw-r--r--crates/bot-config/Cargo.toml23
-rw-r--r--crates/bot-consts/Cargo.toml23
-rw-r--r--crates/bot-error/Cargo.toml23
-rw-r--r--crates/bot-error/src/lib.rs1
-rw-r--r--crates/bot-http/Cargo.toml26
-rw-r--r--crates/bot-http/src/github.rs35
-rw-r--r--crates/bot-http/src/lib.rs63
-rw-r--r--crates/bot-http/src/teawie.rs24
-rw-r--r--crates/bot-jobs/Cargo.toml29
-rw-r--r--crates/bot-jobs/src/lib.rs30
-rw-r--r--crates/bot-jobs/src/repo.rs77
-rw-r--r--crates/bot/Cargo.toml26
-rw-r--r--crates/discord-bot/Cargo.toml31
-rw-r--r--crates/discord-bot/src/commands/about.rs (renamed from crates/bot-commands/src/about.rs)22
-rw-r--r--crates/discord-bot/src/commands/mod.rs (renamed from crates/bot-commands/src/lib.rs)0
-rw-r--r--crates/discord-bot/src/commands/ping.rs (renamed from crates/bot-commands/src/ping.rs)5
-rw-r--r--crates/discord-bot/src/commands/track.rs133
-rw-r--r--crates/discord-bot/src/config.rs (renamed from crates/bot-config/src/lib.rs)4
-rw-r--r--crates/discord-bot/src/consts.rs (renamed from crates/bot-consts/src/lib.rs)0
-rw-r--r--crates/discord-bot/src/handler.rs (renamed from crates/bot-client/src/handler.rs)20
-rw-r--r--crates/discord-bot/src/jobs.rs36
-rw-r--r--crates/discord-bot/src/lib.rs (renamed from crates/bot-client/src/lib.rs)19
-rw-r--r--crates/discord-bot/src/main.rs (renamed from crates/bot/src/main.rs)4
-rw-r--r--crates/git-tracker/Cargo.toml28
-rw-r--r--crates/git-tracker/src/lib.rs33
-rw-r--r--crates/git-tracker/src/managed_repository.rs95
-rw-r--r--crates/git-tracker/src/tracker.rs12
-rw-r--r--crates/nixpkgs-tracker-http/Cargo.toml22
-rw-r--r--crates/nixpkgs-tracker-http/src/github.rs40
-rw-r--r--crates/nixpkgs-tracker-http/src/lib.rs28
-rw-r--r--crates/nixpkgs-tracker-http/src/model.rs (renamed from crates/bot-http/src/model.rs)6
-rw-r--r--crates/nixpkgs-tracker-http/src/teawie.rs30
-rw-r--r--flake.lock22
-rw-r--r--flake.nix97
-rw-r--r--nix/containerize.nix16
-rw-r--r--nix/package.nix3
-rw-r--r--nix/static.nix47
-rw-r--r--treefmt.nix5
47 files changed, 708 insertions, 878 deletions
diff --git a/.env.template b/.env.template
index 86fc934..45cb623 100644
--- a/.env.template
+++ b/.env.template
@@ -5,5 +5,7 @@ DISCORD_BOT_TOKEN=""
BOT_NIXPKGS_PATH=""
BOT_NIXPKGS_BRANCHES="staging,staging-next,master,nixpkgs-unstable,nixos-unstable-small,nixos-unstable,nixos-24.05-small,nixos-24.05,nixpkgs-24.05-darwin"
-RUST_LOG="bot=debug,warn"
+RUST_LOG="git_tracker=debug,discord_bot=debug,warn"
+# For production
+# RUST_LOG="discord_bot=info,warn"
RUST_BACKTRACE=1
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 365325d..c3f7a7e 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -5,39 +5,60 @@ on:
branches: [main]
paths:
- "**.nix"
- - "flake.lock"
- "**.rs"
- - "Cargo.toml"
+ - ".github/workflows/ci.yaml"
- "Cargo.lock"
+ - "Cargo.toml"
+ - "flake.lock"
pull_request:
paths:
- "**.nix"
- - "flake.lock"
- "**.rs"
- - "Cargo.toml"
+ - ".github/workflows/ci.yaml"
- "Cargo.lock"
+ - "Cargo.toml"
+ - "flake.lock"
workflow_dispatch:
jobs:
build:
name: Build
- runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ os: [macos-latest, windows-latest]
+
+ runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust
- uses: dtolnay/rust-toolchain@stable
-
- - name: Setup Rust cache
- uses: Swatinem/rust-cache@v2
+ uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Run build
run: |
cargo build --locked --release
+ nix:
+ name: Nix
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Install Nix
+ uses: DeterminateSystems/nix-installer-action@v13
+
+ - name: Setup Nix cache
+ uses: DeterminateSystems/magic-nix-cache-action@v7
+
+ - name: Run build
+ run: nix build --print-build-logs --show-trace
+
treefmt:
name: Treefmt
@@ -52,11 +73,11 @@ jobs:
- name: Run check
run: |
- nix flake check --print-build-logs --show-trace
+ nix fmt -- --fail-on-change
release-gate:
name: CI Release gate
- needs: [build, treefmt]
+ needs: [build, nix, treefmt]
runs-on: ubuntu-latest
diff --git a/.github/workflows/clippy.yaml b/.github/workflows/clippy.yaml
index 2d3ea70..c94f6ce 100644
--- a/.github/workflows/clippy.yaml
+++ b/.github/workflows/clippy.yaml
@@ -3,15 +3,17 @@ name: Clippy
on:
push:
paths:
- - 'Cargo.toml'
- - 'Cargo.lock'
- '**.rs'
+ - '.github/workflows/clippy.yaml'
+ - 'Cargo.lock'
+ - 'Cargo.toml'
branches: [main]
pull_request:
paths:
- - 'Cargo.toml'
- - 'Cargo.lock'
- '**.rs'
+ - '.github/workflows/clippy.yaml'
+ - 'Cargo.lock'
+ - 'Cargo.toml'
workflow_dispatch:
jobs:
@@ -27,33 +29,21 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@stable
- with:
- components: "clippy"
-
- - name: Setup Rust cache
- uses: Swatinem/rust-cache@v2
+ - name: Install Nix
+ uses: DeterminateSystems/nix-installer-action@v13
- - name: Install SARIF tools
- run: |
- cargo install clippy-sarif sarif-fmt
-
- - name: Fetch Cargo deps
- run: |
- cargo fetch --locked
+ - name: Setup Nix cache
+ uses: DeterminateSystems/magic-nix-cache-action@v7
- name: Run Clippy
- continue-on-error: true
+ id: clippy-run
run: |
- cargo clippy \
- --all-features \
- --all-targets \
- --message-format=json \
- | clippy-sarif | tee /tmp/clippy.sarif | sarif-fmt
+ nix build --print-build-logs .#checks.x86_64-linux.clippy-sarif
+ [ -L result ] || exit 1
+ echo "sarif-file=$(readlink -f result)" >> "$GITHUB_OUTPUT"
- name: Upload results
uses: github/codeql-action/upload-sarif@v3
with:
- sarif_file: /tmp/clippy.sarif
+ sarif_file: ${{ steps.clippy-run.outputs.sarif-file }}
wait-for-processing: true
diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml
index 4fba73a..efce40e 100644
--- a/.github/workflows/docker.yaml
+++ b/.github/workflows/docker.yaml
@@ -5,17 +5,19 @@ on:
branches: [main]
paths:
- "**.nix"
- - "flake.lock"
- "**.rs"
- - "Cargo.toml"
+ - ".github/workflows/docker.yaml"
- "Cargo.lock"
+ - "Cargo.toml"
+ - "flake.lock"
pull_request:
paths:
- "**.nix"
- - "flake.lock"
- "**.rs"
- - "Cargo.toml"
+ - ".github/workflows/docker.yaml"
- "Cargo.lock"
+ - "Cargo.toml"
+ - "flake.lock"
workflow_dispatch:
jobs:
@@ -25,7 +27,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- arch: [x86_64, arm64]
+ arch: [amd64, arm64]
runs-on: ubuntu-latest
@@ -111,7 +113,7 @@ jobs:
env:
TAG: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
run: |
- architectures=("x86_64" "arm64")
+ architectures=("amd64" "arm64")
for arch in "${architectures[@]}"; do
docker load < images/container-"$arch"/*.tar.gz
docker tag nixpkgs-tracker-bot:latest-"$arch" "$TAG"-"$arch"
@@ -119,7 +121,7 @@ jobs:
done
docker manifest create "$TAG" \
- --amend "$TAG"-x86_64 \
+ --amend "$TAG"-amd64 \
--amend "$TAG"-arm64
docker manifest push "$TAG"
diff --git a/Cargo.lock b/Cargo.lock
index ede0690..d33533f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -58,9 +58,9 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
@@ -171,67 +171,6 @@ dependencies = [
]
[[package]]
-name = "bot-client"
-version = "0.2.0"
-dependencies = [
- "bot-commands",
- "bot-config",
- "bot-consts",
- "bot-error",
- "bot-http",
- "bot-jobs",
- "log",
- "serenity",
- "tokio",
-]
-
-[[package]]
-name = "bot-commands"
-version = "0.2.0"
-dependencies = [
- "bot-config",
- "bot-consts",
- "bot-error",
- "bot-http",
- "git-tracker",
- "log",
- "serenity",
-]
-
-[[package]]
-name = "bot-config"
-version = "0.2.0"
-
-[[package]]
-name = "bot-consts"
-version = "0.2.0"
-
-[[package]]
-name = "bot-error"
-version = "0.2.0"
-
-[[package]]
-name = "bot-http"
-version = "0.2.0"
-dependencies = [
- "log",
- "reqwest 0.12.5",
- "serde",
-]
-
-[[package]]
-name = "bot-jobs"
-version = "0.2.0"
-dependencies = [
- "bot-config",
- "bot-consts",
- "bot-error",
- "git2",
- "log",
- "tokio",
-]
-
-[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -433,6 +372,20 @@ dependencies = [
]
[[package]]
+name = "discord-bot"
+version = "0.2.0"
+dependencies = [
+ "dotenvy",
+ "env_logger",
+ "eyre",
+ "git-tracker",
+ "log",
+ "nixpkgs-tracker-http",
+ "serenity",
+ "tokio",
+]
+
+[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -496,6 +449,16 @@ dependencies = [
]
[[package]]
+name = "eyre"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
+
+[[package]]
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -650,9 +613,9 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.18.3"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
+checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
dependencies = [
"bitflags 2.5.0",
"libc",
@@ -923,6 +886,12 @@ dependencies = [
]
[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -982,9 +951,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libgit2-sys"
-version = "0.16.2+1.7.2"
+version = "0.17.0+1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
+checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
dependencies = [
"cc",
"libc",
@@ -1086,14 +1055,12 @@ dependencies = [
]
[[package]]
-name = "nixpkgs-tracker-bot"
+name = "nixpkgs-tracker-http"
version = "0.2.0"
dependencies = [
- "bot-client",
- "bot-error",
- "dotenvy",
- "env_logger",
- "tokio",
+ "log",
+ "reqwest 0.12.5",
+ "serde",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index daa9251..15230b3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,32 +1,29 @@
[workspace]
+resolver = "2"
members = [
- "crates/bot",
- "crates/bot-client",
- "crates/bot-config",
- "crates/bot-consts",
- "crates/bot-error",
- "crates/bot-http",
- "crates/bot-jobs",
- "crates/git-tracker"
+ "crates/*",
]
-resolver = "2"
+
+[workspace.package]
+version = "0.2.0"
+authors = ["seth <getchoo at tuta dot io>"]
+edition = "2021"
+repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
+license = "MIT"
[workspace.dependencies]
-bot = { path = "./crates/bot" }
-bot-client = { path = "./crates/bot-client" }
-bot-commands = { path = "./crates/bot-commands" }
-bot-config = { path = "./crates/bot-config" }
-bot-consts = { path = "./crates/bot-consts" }
-bot-error = { path = "./crates/bot-error" }
-bot-http = { path = "./crates/bot-http" }
-bot-jobs = { path = "./crates/bot-jobs" }
git-tracker = { path = "./crates/git-tracker" }
+nixpkgs-tracker-http = { path = "./crates/nixpkgs-tracker-http" }
-git2 = { version = "0.18.3", default-features = false }
log = "0.4.22"
-serenity = { version = "0.12.2", features = ["unstable_discord_api"] }
-tokio = { version = "1.39.2", features = [
- "macros",
- "rt-multi-thread",
- "signal"
-] }
+
+[workspace.lints.rust]
+unsafe_code = "forbid"
+
+[workspace.lints.clippy]
+complexity = "warn"
+correctness = "deny"
+pedantic = "warn"
+perf = "warn"
+style = "warn"
+suspicious = "deny"
diff --git a/crates/bot-client/Cargo.toml b/crates/bot-client/Cargo.toml
deleted file mode 100644
index a2ba2a0..0000000
--- a/crates/bot-client/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-name = "bot-client"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Discord client for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-bot-commands = { workspace = true }
-bot-config = { workspace = true }
-bot-consts = { workspace = true }
-bot-error = { workspace = true }
-bot-http = { workspace = true }
-bot-jobs = { workspace = true }
-log = { workspace = true }
-serenity = { workspace = true }
-tokio = { workspace = true }
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-commands/Cargo.toml b/crates/bot-commands/Cargo.toml
deleted file mode 100644
index 3594c70..0000000
--- a/crates/bot-commands/Cargo.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-[package]
-name = "bot-commands"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Discord application commands for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-bot-config = { workspace = true }
-bot-consts = { workspace = true }
-bot-error = { workspace = true }
-bot-http = { workspace = true }
-git-tracker = { workspace = true }
-log = { workspace = true }
-serenity = { workspace = true }
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
-# NOTE: THIS ISN'T IN OTHER CRATES BUT IS HERE
-# this is because we don't really care about error docs here
-# and it could mess with poise's comment system in the future :p
-missing-errors-doc = "allow"
diff --git a/crates/bot-commands/src/track.rs b/crates/bot-commands/src/track.rs
deleted file mode 100644
index 1f22d0e..0000000
--- a/crates/bot-commands/src/track.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use bot_config::Config;
-use bot_consts::{NIXPKGS_REMOTE, NIXPKGS_URL};
-use bot_error::Error;
-use bot_http::{self as http, GithubClientExt};
-use git_tracker::Tracker;
-
-use log::trace;
-use serenity::all::CreateEmbed;
-use serenity::builder::{CreateCommand, CreateCommandOption, CreateInteractionResponseFollowup};
-use serenity::model::application::{
- CommandInteraction, CommandOptionType, InstallationContext, ResolvedOption, ResolvedValue,
-};
-use serenity::prelude::Context;
-
-const REPO_OWNER: &str = "NixOS";
-const REPO_NAME: &str = "nixpkgs";
-
-/// Collect the status of the commit SHA [`commit_sha`] in each of the nixpkgs
-/// branches in [`branches`], using the repository at path [`repository_path`]
-///
-/// # 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
-fn collect_statuses_in<'a>(
- repository_path: &str,
- commit_sha: &str,
- branches: impl IntoIterator<Item = &'a String>,
-) -> Result<Vec<String>, Error> {
- // start tracking nixpkgs
- let tracker = Tracker::from_path(repository_path)?;
-
- // check to see what branches it's in
- let mut status_results = vec![];
- for branch_name in branches {
- trace!("Checking for commit in {branch_name}");
- let full_branch_name = format!("{NIXPKGS_REMOTE}/{branch_name}");
- let has_pr = tracker.branch_contains_sha(&full_branch_name, commit_sha)?;
-
- if has_pr {
- status_results.push(format!("`{branch_name}` ✅"));
- }
- }
-
- Ok(status_results)
-}
-
-pub async fn respond(
- ctx: &Context,
- http: &http::Client,
- config: &Config,
- command: &CommandInteraction,
-) -> Result<(), Error> {
- // this will probably take a while
- command.defer(&ctx).await?;
-
- let options = command.data.options();
- let Some(ResolvedOption {
- value: ResolvedValue::Integer(pr),
- ..
- }) = options.first()
- else {
- let resp = CreateInteractionResponseFollowup::new()
- .content("Please provide a valid pull request!");
- command.create_followup(&ctx, resp).await?;
-
- return Ok(());
- };
-
- let Ok(pr_id) = u64::try_from(*pr) else {
- let resp =
- CreateInteractionResponseFollowup::new().content("PR numbers aren't negative...");
- command.create_followup(&ctx, resp).await?;
-
- return Ok(());
- };
-
- // find out what commit our PR was merged in
- let Some(commit_sha) = http.merge_commit_for(REPO_OWNER, REPO_NAME, pr_id).await? else {
- let response = CreateInteractionResponseFollowup::new()
- .content("It seems this pull request is very old. I can't track it");
- command.create_followup(&ctx, response).await?;
-
- return Ok(());
- };
-
- let status_results = collect_statuses_in(
- &config.nixpkgs_path,
- &commit_sha,
- config.nixpkgs_branches.iter(),
- )?;
-
- // if we don't find the commit in any branches from above, we can pretty safely assume
- // it's an unmerged PR
- let embed_description: String = if status_results.is_empty() {
- "It doesn't look like this PR has been merged yet! (or maybe I just haven't updated)"
- .to_string()
- } else {
- status_results.join("\n")
- };
-
- let embed = CreateEmbed::new()
- .title(format!("Nixpkgs PR #{} Status", *pr))
- .url(format!("{NIXPKGS_URL}/pull/{pr}"))
- .description(embed_description);
-
- let resp = CreateInteractionResponseFollowup::new().embed(embed);
- command.create_followup(&ctx, resp).await?;
-
- Ok(())
-}
-
-pub fn register() -> CreateCommand {
- CreateCommand::new("track")
- .description("Track a nixpkgs PR")
- .add_integration_type(InstallationContext::User)
- .add_option(
- CreateCommandOption::new(CommandOptionType::Integer, "pull_request", "PR to track")
- .required(true),
- )
-}
diff --git a/crates/bot-config/Cargo.toml b/crates/bot-config/Cargo.toml
deleted file mode 100644
index 57b9a67..0000000
--- a/crates/bot-config/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-name = "bot-config"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Configuration for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-consts/Cargo.toml b/crates/bot-consts/Cargo.toml
deleted file mode 100644
index 16d7726..0000000
--- a/crates/bot-consts/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-name = "bot-consts"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Constants for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-error/Cargo.toml b/crates/bot-error/Cargo.toml
deleted file mode 100644
index c6f6ed1..0000000
--- a/crates/bot-error/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-name = "bot-error"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Shared Err variant used for (most of) nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-error/src/lib.rs b/crates/bot-error/src/lib.rs
deleted file mode 100644
index f34e60e..0000000
--- a/crates/bot-error/src/lib.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub type Error = Box<dyn std::error::Error + Send + Sync>;
diff --git a/crates/bot-http/Cargo.toml b/crates/bot-http/Cargo.toml
deleted file mode 100644
index 0888fda..0000000
--- a/crates/bot-http/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "bot-http"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "HTTP client for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-log = { workspace = true }
-reqwest = { version = "0.12.5", default-features = false, features = ["charset", "http2", "rustls-tls", "json"] }
-serde = { version = "1.0.207", features = ["derive"] }
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-http/src/github.rs b/crates/bot-http/src/github.rs
deleted file mode 100644
index 7822eb8..0000000
--- a/crates/bot-http/src/github.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use super::{ClientExt as _, Error};
-use crate::model::PullRequest;
-
-use std::future::Future;
-
-const GITHUB_API: &str = "https://api.github.com";
-
-pub trait ClientExt {
- /// Get the commit that merged [`pr`] in [`repo_owner`]/[`repo_name`]
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if the merge commit cannot be found
- fn merge_commit_for(
- &self,
- repo_owner: &str,
- repo_name: &str,
- pr: u64,
- ) -> impl Future<Output = Result<Option<String>, Error>> + Send;
-}
-
-impl ClientExt for super::Client {
- async fn merge_commit_for(
- &self,
- repo_owner: &str,
- repo_name: &str,
- pr: u64,
- ) -> Result<Option<String>, Error> {
- let url = format!("{GITHUB_API}/repos/{repo_owner}/{repo_name}/pulls/{pr}");
- let resp: PullRequest = self.get_json(&url).await?;
- let merge_commit = resp.merge_commit_sha;
-
- Ok(merge_commit)
- }
-}
diff --git a/crates/bot-http/src/lib.rs b/crates/bot-http/src/lib.rs
deleted file mode 100644
index ab32cd4..0000000
--- a/crates/bot-http/src/lib.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use std::future::Future;
-
-use log::trace;
-use serde::de::DeserializeOwned;
-
-mod github;
-mod model;
-mod teawie;
-
-pub use github::ClientExt as GithubClientExt;
-pub use teawie::ClientExt as TeawieClientExt;
-
-pub type Client = reqwest::Client;
-pub type Response = reqwest::Response;
-pub type Error = reqwest::Error;
-
-/// Fun trait for functions we use with [Client]
-pub trait ClientExt {
- fn default() -> Self;
- fn get_request(&self, url: &str) -> impl Future<Output = Result<Response, Error>> + Send;
- fn get_json<T: DeserializeOwned>(
- &self,
- url: &str,
- ) -> impl Future<Output = Result<T, Error>> + Send;
-}
-
-impl ClientExt for Client {
- /// Create the default [`Client`]
- fn default() -> Self {
- reqwest::Client::builder()
- .user_agent(format!(
- "nixpkgs-tracker-bot/{}",
- option_env!("CARGO_PKG_VERSION").unwrap_or_else(|| "development")
- ))
- .build()
- .unwrap()
- }
-
- /// Perform a GET request to [`url`]
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if the request fails
- async fn get_request(&self, url: &str) -> Result<Response, Error> {
- trace!("Making GET request to {url}");
-
- let resp = self.get(url).send().await?;
- resp.error_for_status_ref()?;
-
- Ok(resp)
- }
-
- /// Perform a GET request to [`url`] and decode the json response
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if the request fails or cannot be deserialized
- async fn get_json<T: DeserializeOwned>(&self, url: &str) -> Result<T, Error> {
- let resp = self.get_request(url).await?;
- let json = resp.json().await?;
- Ok(json)
- }
-}
diff --git a/crates/bot-http/src/teawie.rs b/crates/bot-http/src/teawie.rs
deleted file mode 100644
index ea4f53e..0000000
--- a/crates/bot-http/src/teawie.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use super::{ClientExt as _, Error};
-use crate::model::RandomTeawie;
-
-use std::future::Future;
-
-const TEAWIE_API: &str = "https://api.getchoo.com";
-
-pub trait ClientExt {
- /// Get a random teawie
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if the request fails or the response cannot be deserialized
- fn random_teawie(&self) -> impl Future<Output = Result<Option<String>, Error>> + Send;
-}
-
-impl ClientExt for super::Client {
- async fn random_teawie(&self) -> Result<Option<String>, Error> {
- let url = format!("{TEAWIE_API}/random_teawie");
- let resp: RandomTeawie = self.get_json(&url).await?;
-
- Ok(resp.url)
- }
-}
diff --git a/crates/bot-jobs/Cargo.toml b/crates/bot-jobs/Cargo.toml
deleted file mode 100644
index 21b0248..0000000
--- a/crates/bot-jobs/Cargo.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[package]
-name = "bot-jobs"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "Background jobs for nixpkgs-tracker-bot"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-publish = false
-
-[dependencies]
-bot-config = { workspace = true }
-bot-consts = { workspace = true }
-bot-error = { workspace = true }
-git2 = { workspace = true, features = ["https"] }
-log = { workspace = true }
-tokio = { workspace = true }
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/bot-jobs/src/lib.rs b/crates/bot-jobs/src/lib.rs
deleted file mode 100644
index d65c929..0000000
--- a/crates/bot-jobs/src/lib.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use bot_config::Config;
-use bot_error::Error;
-
-use std::time::Duration;
-
-use log::error;
-
-mod repo;
-
-/// Run our jobs an initial time, then loop them on a separate thread
-///
-/// # Errors
-///
-/// Will return [`Err`] if any jobs fail
-pub fn dispatch(config: Config) -> Result<(), Error> {
- repo::fetch_or_update_repository(&config.nixpkgs_path, &config.nixpkgs_branches)?;
-
- tokio::spawn(async move {
- loop {
- tokio::time::sleep(Duration::from_secs(repo::TTL_SECS)).await;
- if let Err(why) =
- repo::fetch_or_update_repository(&config.nixpkgs_path, &config.nixpkgs_branches)
- {
- error!("Failed to fetch or update repository!\n{why:?}");
- };
- }
- });
-
- Ok(())
-}
diff --git a/crates/bot-jobs/src/repo.rs b/crates/bot-jobs/src/repo.rs
deleted file mode 100644
index 4d3e214..0000000
--- a/crates/bot-jobs/src/repo.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use bot_consts::{NIXPKGS_REMOTE, NIXPKGS_URL};
-use bot_error::Error;
-
-use std::{io::Write, path::Path};
-
-use git2::{AutotagOption, FetchOptions, RemoteCallbacks, Repository};
-use log::{debug, info, trace, warn};
-
-pub const TTL_SECS: u64 = 60 * 5; // 5 minutes
-
-// much of this is shamelessly lifted from
-// https://github.com/rust-lang/git2-rs/blob/9a5c9706ff578c936be644dd1e8fe155bdc4d129/examples/pull.rs
-
-/// 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(repository: &Repository, branches: &[String]) -> Result<(), Error> {
- let mut remote = repository.find_remote(NIXPKGS_REMOTE)?;
- // download all the refs
- remote.download(branches, Some(&mut fetch_options()))?;
- remote.disconnect()?;
- // and (hopefully) update what they refer to for later
- remote.update_tips(None, true, AutotagOption::Auto, None)?;
-
- Ok(())
-}
-
-pub fn fetch_or_update_repository(path: &str, branches: &[String]) -> Result<(), Error> {
- // Open our repository or clone it if it doesn't exist
- let path = Path::new(path);
- let repository = if path.exists() {
- Repository::open(path)?
- } else {
- warn!(
- "Couldn't find repository at {}! Cloning a fresh one from {NIXPKGS_URL}",
- path.display()
- );
- Repository::clone(NIXPKGS_URL, path)?;
- info!("Finished cloning to {}", path.display());
-
- // bail early as we already have a fresh copy
- return Ok(());
- };
-
- debug!("Updating repository at {}", path.display());
- update_branches_in(&repository, branches)?;
- debug!("Finished updating!");
-
- Ok(())
-}
diff --git a/crates/bot/Cargo.toml b/crates/bot/Cargo.toml
deleted file mode 100644
index 69feace..0000000
--- a/crates/bot/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "nixpkgs-tracker-bot"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "A small Discord app that helps you track where nixpkgs PRs have reached"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
-
-[dependencies]
-bot-error = { workspace = true }
-bot-client = { workspace = true }
-dotenvy = "0.15.7"
-env_logger = "0.11.5"
-tokio = { workspace = true }
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
diff --git a/crates/discord-bot/Cargo.toml b/crates/discord-bot/Cargo.toml
new file mode 100644
index 0000000..dd35306
--- /dev/null
+++ b/crates/discord-bot/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "discord-bot"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+description = "Small Discord app that helps you track where nixpkgs PRs have reached"
+repository.workspace = true
+license.workspace = true
+
+publish = false
+
+[[bin]]
+name = "nixpkgs-tracker-bot"
+path = "src/main.rs"
+
+[dependencies]
+dotenvy = "0.15.7"
+env_logger = "0.11.5"
+eyre = "0.6.12"
+git-tracker.workspace = true
+log.workspace = true
+nixpkgs-tracker-http.workspace = true
+serenity = { version = "0.12.2", features = ["unstable_discord_api"] }
+tokio = { version = "1.39.2", features = [
+ "macros",
+ "rt-multi-thread",
+ "signal"
+] }
+
+[lints]
+workspace = true
diff --git a/crates/bot-commands/src/about.rs b/crates/discord-bot/src/commands/about.rs
index 2e5efae..e663faf 100644
--- a/crates/bot-commands/src/about.rs
+++ b/crates/discord-bot/src/commands/about.rs
@@ -1,6 +1,9 @@
-use bot_error::Error;
-use bot_http::TeawieClientExt;
+use std::sync::Arc;
+use crate::http::TeawieClientExt;
+
+use eyre::Result;
+use log::warn;
use serenity::builder::{
CreateCommand, CreateEmbed, CreateEmbedFooter, CreateInteractionResponse,
CreateInteractionResponseMessage,
@@ -11,11 +14,10 @@ use serenity::prelude::Context;
const VERSION: &str = env!("CARGO_PKG_VERSION");
const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
-pub async fn respond(
- ctx: &Context,
- http: &bot_http::Client,
- command: &CommandInteraction,
-) -> Result<(), Error> {
+pub async fn respond<T>(ctx: &Context, http: &Arc<T>, command: &CommandInteraction) -> Result<()>
+where
+ T: TeawieClientExt,
+{
let mut embed = CreateEmbed::new()
.title("About nixpkgs-tracker-bot")
.description("I help track what branches PRs to nixpkgs have reached. If you've used [Nixpkgs Pull Request Tracker](https://nixpk.gs/pr-tracker.html), you probably know what this is about.")
@@ -25,9 +27,13 @@ pub async fn respond(
("Issues/Feature Requests", &format!("[getchoo/nixpkgs-tracker-bot/issues]({REPOSITORY}/issues)"), true)
]);
- if let Some(teawie_url) = http.random_teawie().await? {
+ let random_teawie = http.random_teawie().await?;
+
+ if let Some(teawie_url) = random_teawie.url {
let footer = CreateEmbedFooter::new("Images courtesy of @sympathytea");
embed = embed.image(teawie_url).footer(footer);
+ } else if let Some(error) = random_teawie.error {
+ warn!("Error from TeawieAPI: {error:#?}");
};
let message = CreateInteractionResponseMessage::new().embed(embed);
diff --git a/crates/bot-commands/src/lib.rs b/crates/discord-bot/src/commands/mod.rs
index 79fce17..79fce17 100644
--- a/crates/bot-commands/src/lib.rs
+++ b/crates/discord-bot/src/commands/mod.rs
diff --git a/crates/bot-commands/src/ping.rs b/crates/discord-bot/src/commands/ping.rs
index b18a0b6..30150dc 100644
--- a/crates/bot-commands/src/ping.rs
+++ b/crates/discord-bot/src/commands/ping.rs
@@ -1,12 +1,11 @@
-use bot_error::Error;
-
+use eyre::Result;
use serenity::builder::{
CreateCommand, CreateInteractionResponse, CreateInteractionResponseMessage,
};
use serenity::model::application::{CommandInteraction, InstallationContext};
use serenity::prelude::Context;
-pub async fn respond(ctx: &Context, command: &CommandInteraction) -> Result<(), Error> {
+pub async fn respond(ctx: &Context, command: &CommandInteraction) -> Result<()> {
let message = CreateInteractionResponseMessage::new().content("Pong!");
let response = CreateInteractionResponse::Message(message);
command.create_response(&ctx, response).await?;
diff --git a/crates/discord-bot/src/commands/track.rs b/crates/discord-bot/src/commands/track.rs
new file mode 100644
index 0000000..f071ebf
--- /dev/null
+++ b/crates/discord-bot/src/commands/track.rs
@@ -0,0 +1,133 @@
+use crate::{config::Config, consts::NIXPKGS_REMOTE, http::GitHubClientExt};
+
+use std::sync::Arc;
+
+use eyre::Result;
+use log::debug;
+use serenity::builder::{
+ CreateCommand, CreateCommandOption, CreateEmbed, CreateInteractionResponseFollowup,
+};
+use serenity::model::{
+ application::{
+ CommandInteraction, CommandOptionType, InstallationContext, ResolvedOption, ResolvedValue,
+ },
+ Timestamp,
+};
+use serenity::prelude::Context;
+
+const REPO_OWNER: &str = "NixOS";
+const REPO_NAME: &str = "nixpkgs";
+
+pub async fn respond<T>(
+ ctx: &Context,
+ http: &Arc<T>,
+ config: &Config,
+ command: &CommandInteraction,
+) -> Result<()>
+where
+ T: GitHubClientExt,
+{
+ // this will probably take a while
+ command.defer(&ctx).await?;
+
+ let options = command.data.options();
+ let Some(ResolvedOption {
+ value: ResolvedValue::Integer(pr),
+ ..
+ }) = options.first()
+ else {
+ let resp = CreateInteractionResponseFollowup::new()
+ .content("PR numbers aren't negative or that big...");
+ command.create_followup(&ctx, resp).await?;
+
+ return Ok(());
+ };
+
+ let Ok(id) = u64::try_from(*pr) else {
+ let resp = CreateInteractionResponseFollowup::new()
+ .content("PR numbers aren't negative or that big...");
+ command.create_followup(&ctx, resp).await?;
+
+ return Ok(());
+ };
+
+ // find out what commit our PR was merged in
+ let pull_request = http.pull_request(REPO_OWNER, REPO_NAME, id).await?;
+ if !pull_request.merged {
+ let response = CreateInteractionResponseFollowup::new()
+ .content("It looks like that PR isn't merged yet! Try again when it is 😄");
+ command.create_followup(&ctx, response).await?;
+
+ return Ok(());
+ }
+
+ // seems older PRs may not have this
+ let Some(commit_sha) = pull_request.merge_commit_sha else {
+ let response = CreateInteractionResponseFollowup::new()
+ .content("It seems this pull request is very old. I can't track it");
+ command.create_followup(&ctx, response).await?;
+
+ 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
+ .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()
+ })
+ .collect();
+
+ // if we didn't find any, bail
+ if found_branches.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?;
+
+ return Ok(());
+ }
+
+ let mut embed = CreateEmbed::new()
+ .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)),
+ );
+
+ if let Some(merged_at) = pull_request.merged_at {
+ if let Ok(timestamp) = Timestamp::parse(&merged_at) {
+ embed = embed.timestamp(timestamp);
+ } else {
+ debug!("Couldn't parse timestamp from GitHub! Ignoring.");
+ }
+ } else {
+ debug!("Couldn't find `merged_at` information for a supposedly merged PR! Ignoring.");
+ }
+
+ let resp = CreateInteractionResponseFollowup::new().embed(embed);
+ command.create_followup(&ctx, resp).await?;
+
+ Ok(())
+}
+
+pub fn register() -> CreateCommand {
+ CreateCommand::new("track")
+ .description("Track a nixpkgs PR")
+ .add_integration_type(InstallationContext::User)
+ .add_option(
+ CreateCommandOption::new(CommandOptionType::Integer, "pull_request", "PR to track")
+ .required(true),
+ )
+}
diff --git a/crates/bot-config/src/lib.rs b/crates/discord-bot/src/config.rs
index 0691884..5076eb9 100644
--- a/crates/bot-config/src/lib.rs
+++ b/crates/discord-bot/src/config.rs
@@ -1,3 +1,5 @@
+use crate::consts::NIXPKGS_REMOTE;
+
use std::env;
/// The Discord client's configuration
@@ -14,7 +16,7 @@ impl Config {
fn split_string_list(branches: &str) -> Vec<String> {
branches
.split(',')
- .map(|branch| branch.trim().to_string())
+ .map(|branch| format!("{NIXPKGS_REMOTE}/{}", branch.trim()))
.collect()
}
diff --git a/crates/bot-consts/src/lib.rs b/crates/discord-bot/src/consts.rs
index 9396da0..9396da0 100644
--- a/crates/bot-consts/src/lib.rs
+++ b/crates/discord-bot/src/consts.rs
diff --git a/crates/bot-client/src/handler.rs b/crates/discord-bot/src/handler.rs
index 2cd0082..4abb99b 100644
--- a/crates/bot-client/src/handler.rs
+++ b/crates/discord-bot/src/handler.rs
@@ -1,6 +1,6 @@
-use crate::{SharedConfig, SharedHttp};
-use bot_error::Error;
+use crate::{commands, SharedConfig, SharedHttp};
+use eyre::{OptionExt, Result};
use log::{debug, error, info, trace, warn};
use serenity::all::CreateBotAuthParameters;
use serenity::async_trait;
@@ -19,8 +19,8 @@ use serenity::prelude::{Context, EventHandler};
pub struct Handler;
impl Handler {
- async fn register_commands(&self, ctx: &Context) -> Result<(), Error> {
- let commands = bot_commands::to_vec();
+ async fn register_commands(&self, ctx: &Context) -> Result<()> {
+ let commands = commands::to_vec();
let commands_len = commands.len();
for command in commands {
Command::create_global_command(&ctx.http, command).await?;
@@ -31,7 +31,7 @@ impl Handler {
}
/// Dispatch our commands from a [`CommandInteraction`]
- async fn dispatch_command(ctx: &Context, command: &CommandInteraction) -> Result<(), Error> {
+ async fn dispatch_command(ctx: &Context, command: &CommandInteraction) -> Result<()> {
let command_name = command.data.name.as_str();
// grab our configuration & http client from the aether
@@ -39,19 +39,19 @@ impl Handler {
let read = ctx.data.read().await;
let http = read
.get::<SharedHttp>()
- .ok_or("Couldn't get shared HTTP client! WHY??????")?
+ .ok_or_eyre("Couldn't get shared HTTP client! WHY??????")?
.clone();
let config = read
.get::<SharedConfig>()
- .ok_or("Couldn't get shared bot configuration!")?
+ .ok_or_eyre("Couldn't get shared bot configuration!")?
.clone();
(http, config)
};
match command_name {
- "about" => bot_commands::about::respond(ctx, &http, command).await?,
- "ping" => bot_commands::ping::respond(ctx, command).await?,
- "track" => bot_commands::track::respond(ctx, &http, &config, command).await?,
+ "about" => commands::about::respond(ctx, &http, command).await?,
+ "ping" => commands::ping::respond(ctx, command).await?,
+ "track" => commands::track::respond(ctx, &http, &config, command).await?,
_ => {
let message = CreateInteractionResponseMessage::new().content(format!(
"It doesn't look like you can use `{command_name}`. Sorry :("
diff --git a/crates/discord-bot/src/jobs.rs b/crates/discord-bot/src/jobs.rs
new file mode 100644
index 0000000..40d34cc
--- /dev/null
+++ b/crates/discord-bot/src/jobs.rs
@@ -0,0 +1,36 @@
+use crate::{config::Config, consts::NIXPKGS_REMOTE, consts::NIXPKGS_URL};
+
+use std::{path::Path, time::Duration};
+
+use eyre::Result;
+use git_tracker::ManagedRepository;
+use log::error;
+
+const TTL_SECS: u64 = 60 * 5; // 5 minutes
+
+/// Run our jobs an initial time, then loop them on a separate thread
+///
+/// # 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(),
+ };
+
+ managed_repository.fetch_or_update()?;
+
+ tokio::spawn(async move {
+ loop {
+ tokio::time::sleep(Duration::from_secs(TTL_SECS)).await;
+ if let Err(why) = managed_repository.fetch_or_update() {
+ error!("Could not fetch or update repository!\n{why:?}");
+ };
+ }
+ });
+
+ Ok(())
+}
diff --git a/crates/bot-client/src/lib.rs b/crates/discord-bot/src/lib.rs
index 851b853..7ac2e98 100644
--- a/crates/bot-client/src/lib.rs
+++ b/crates/discord-bot/src/lib.rs
@@ -1,15 +1,18 @@
-use bot_config::Config;
-use bot_error::Error;
-use bot_http as http;
-
use std::sync::Arc;
+use eyre::Result;
use log::trace;
use serenity::prelude::{Client, GatewayIntents, TypeMapKey};
+mod commands;
+mod config;
+mod consts;
mod handler;
+mod jobs;
+use config::Config;
use handler::Handler;
+use nixpkgs_tracker_http as http;
/// Container for [`http::Client`]
struct SharedHttp;
@@ -26,7 +29,7 @@ impl TypeMapKey for SharedConfig {
}
/// Fetch our bot token
-fn token() -> Result<String, Error> {
+fn token() -> Result<String> {
let token = std::env::var("DISCORD_BOT_TOKEN")?;
Ok(token)
}
@@ -41,7 +44,7 @@ fn token() -> Result<String, Error> {
/// # Panics
///
/// Will [`panic!`] if the bot token isn't found or the ctrl+c handler can't be made
-pub async fn get() -> Result<Client, Error> {
+pub async fn client() -> Result<Client> {
let token = token().expect("Couldn't find token in environment! Is DISCORD_BOT_TOKEN set?");
let intents = GatewayIntents::default();
@@ -51,7 +54,7 @@ pub async fn get() -> Result<Client, Error> {
.await?;
// add state stuff
- let http_client = <http::Client as http::ClientExt>::default();
+ let http_client = <http::Client as http::Ext>::default();
let config = Config::from_env()?;
{
@@ -73,7 +76,7 @@ pub async fn get() -> Result<Client, Error> {
});
// run our jobs
- bot_jobs::dispatch(config)?;
+ jobs::dispatch(config)?;
Ok(client)
}
diff --git a/crates/bot/src/main.rs b/crates/discord-bot/src/main.rs
index 390e79b..acbf9fd 100644
--- a/crates/bot/src/main.rs
+++ b/crates/discord-bot/src/main.rs
@@ -1,9 +1,9 @@
#[tokio::main]
-async fn main() -> Result<(), bot_error::Error> {
+async fn main() -> eyre::Result<()> {
dotenvy::dotenv().ok();
env_logger::try_init()?;
- let mut client = bot_client::get().await?;
+ let mut client = discord_bot::client().await?;
client.start().await?;
Ok(())
diff --git a/crates/git-tracker/Cargo.toml b/crates/git-tracker/Cargo.toml
index 09584cb..4805502 100644
--- a/crates/git-tracker/Cargo.toml
+++ b/crates/git-tracker/Cargo.toml
@@ -1,27 +1,17 @@
[package]
name = "git-tracker"
-version = "0.2.0"
-edition = "2021"
-
-authors = ["seth <getchoo at tuta dot io>"]
-description = "A library that helps you track commits and branches in a Git repository"
-repository = "https://github.com/getchoo/nixpkgs-tracker-bot"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+description = "Library that helps you track commits and branches in a Git repository"
+repository.workspace = true
publish = false
[dependencies]
-git2 = { workspace = true }
-log = { workspace = true }
+git2 = { version = "0.19.0", default-features = false, features = ["https"] }
+log.workspace = true
thiserror = "1.0.63"
-[lints.rust]
-async_fn_in_trait = "allow"
-unsafe_code = "forbid"
-
-[lints.clippy]
-complexity = "warn"
-correctness = "deny"
-pedantic = "warn"
-perf = "warn"
-style = "warn"
-suspicious = "deny"
+[lints]
+workspace = true
diff --git a/crates/git-tracker/src/lib.rs b/crates/git-tracker/src/lib.rs
index cb0907b..0bf17dc 100644
--- a/crates/git-tracker/src/lib.rs
+++ b/crates/git-tracker/src/lib.rs
@@ -1,4 +1,35 @@
//! A library that helps you track commits and branches in a Git repository
+use log::trace;
+mod managed_repository;
mod tracker;
-pub use tracker::{Error, 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));
+ }
+
+ Ok(status_results)
+}
diff --git a/crates/git-tracker/src/managed_repository.rs b/crates/git-tracker/src/managed_repository.rs
new file mode 100644
index 0000000..0a41bd0
--- /dev/null
+++ b/crates/git-tracker/src/managed_repository.rs
@@ -0,0 +1,95 @@
+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
index e26f82d..e6a3f54 100644
--- a/crates/git-tracker/src/tracker.rs
+++ b/crates/git-tracker/src/tracker.rs
@@ -2,6 +2,11 @@ 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")]
@@ -10,11 +15,6 @@ pub enum Error {
RepositoryPathNotFound(String),
}
-/// Helper struct for tracking Git objects
-pub struct Tracker {
- repository: Repository,
-}
-
impl Tracker {
/// Create a new [`Tracker`] using the repository at [`path`]
///
@@ -76,7 +76,7 @@ impl Tracker {
.repository
.graph_descendant_of(head.id(), commit.id())?;
- Ok(has_commit || is_head)
+ Ok(is_head || has_commit)
}
/// Check if a [`Branch`] named [`branch_name`] has a commit with the SHA [`commit_sha`]
diff --git a/crates/nixpkgs-tracker-http/Cargo.toml b/crates/nixpkgs-tracker-http/Cargo.toml
new file mode 100644
index 0000000..45b897d
--- /dev/null
+++ b/crates/nixpkgs-tracker-http/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "nixpkgs-tracker-http"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+
+publish = false
+
+[dependencies]
+log.workspace = true
+reqwest = { version = "0.12.5", default-features = false, features = [
+ "charset",
+ "http2",
+ "rustls-tls",
+ "json"
+] }
+serde = { version = "1.0.204", features = ["derive"] }
+
+[lints]
+workspace = true
diff --git a/crates/nixpkgs-tracker-http/src/github.rs b/crates/nixpkgs-tracker-http/src/github.rs
new file mode 100644
index 0000000..12ee832
--- /dev/null
+++ b/crates/nixpkgs-tracker-http/src/github.rs
@@ -0,0 +1,40 @@
+use super::{Error, PullRequest};
+
+use std::future::Future;
+
+use log::trace;
+
+const GITHUB_API: &str = "https://api.github.com";
+
+pub trait Ext {
+ /// GET `/repos/{repo_owner}/{repo_name}/pulls/{id}`
+ ///
+ /// # Errors
+ ///
+ /// Will return [`Err`] if the merge commit cannot be found
+ fn pull_request(
+ &self,
+ repo_owner: &str,
+ repo_name: &str,
+ id: u64,
+ ) -> impl Future<Output = Result<PullRequest, Error>> + Send;
+}
+
+impl Ext for super::Client {
+ async fn pull_request(
+ &self,
+ repo_owner: &str,
+ repo_name: &str,
+ id: u64,
+ ) -> Result<PullRequest, Error> {
+ let url = format!("{GITHUB_API}/repos/{repo_owner}/{repo_name}/pulls/{id}");
+
+ let request = self.get(&url).build()?;
+ trace!("Making GET request to `{}`", request.url());
+ let response = self.execute(request).await?;
+ response.error_for_status_ref()?;
+ let pull_request: PullRequest = response.json().await?;
+
+ Ok(pull_request)
+ }
+}
diff --git a/crates/nixpkgs-tracker-http/src/lib.rs b/crates/nixpkgs-tracker-http/src/lib.rs
new file mode 100644
index 0000000..873ebb8
--- /dev/null
+++ b/crates/nixpkgs-tracker-http/src/lib.rs
@@ -0,0 +1,28 @@
+mod github;
+mod model;
+mod teawie;
+
+pub use github::Ext as GitHubClientExt;
+pub use model::*;
+pub use teawie::Ext as TeawieClientExt;
+
+pub type Client = reqwest::Client;
+pub type Error = reqwest::Error;
+
+/// Fun trait for functions we use with [Client]
+pub trait Ext {
+ fn default() -> Self;
+}
+
+impl Ext for Client {
+ /// Create the default [`Client`]
+ fn default() -> Self {
+ reqwest::Client::builder()
+ .user_agent(format!(
+ "nixpkgs-tracker-bot/{}",
+ option_env!("CARGO_PKG_VERSION").unwrap_or_else(|| "development")
+ ))
+ .build()
+ .unwrap()
+ }
+}
diff --git a/crates/bot-http/src/model.rs b/crates/nixpkgs-tracker-http/src/model.rs
index afd4717..9439538 100644
--- a/crates/bot-http/src/model.rs
+++ b/crates/nixpkgs-tracker-http/src/model.rs
@@ -3,6 +3,11 @@ use serde::Deserialize;
/// Bad version of `/repos/{owner}/{repo}/pulls/{pull_number}` for Github's api
#[derive(Clone, Debug, Deserialize)]
pub struct PullRequest {
+ pub html_url: String,
+ pub number: u64,
+ pub title: String,
+ pub merged: bool,
+ pub merged_at: Option<String>,
pub merge_commit_sha: Option<String>,
}
@@ -10,4 +15,5 @@ pub struct PullRequest {
#[derive(Clone, Debug, Deserialize)]
pub struct RandomTeawie {
pub url: Option<String>,
+ pub error: Option<String>,
}
diff --git a/crates/nixpkgs-tracker-http/src/teawie.rs b/crates/nixpkgs-tracker-http/src/teawie.rs
new file mode 100644
index 0000000..97af63c
--- /dev/null
+++ b/crates/nixpkgs-tracker-http/src/teawie.rs
@@ -0,0 +1,30 @@
+use crate::{Error, RandomTeawie};
+
+use std::future::Future;
+
+use log::trace;
+
+const TEAWIE_API: &str = "https://api.getchoo.com";
+
+pub trait Ext {
+ /// Get a random teawie
+ ///
+ /// # Errors
+ ///
+ /// Will return [`Err`] if the request fails or the response cannot be deserialized
+ fn random_teawie(&self) -> impl Future<Output = Result<RandomTeawie, Error>> + Send;
+}
+
+impl Ext for super::Client {
+ async fn random_teawie(&self) -> Result<RandomTeawie, Error> {
+ let url = format!("{TEAWIE_API}/random_teawie");
+
+ let request = self.get(&url).build()?;
+ trace!("Making GET request to {}", request.url());
+ let response = self.execute(request).await?;
+ response.error_for_status_ref()?;
+ let random_teawie: RandomTeawie = response.json().await?;
+
+ Ok(random_teawie)
+ }
+}
diff --git a/flake.lock b/flake.lock
index 7a58044..ce9222f 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,26 +1,5 @@
{
"nodes": {
- "fenix": {
- "inputs": {
- "nixpkgs": [
- "nixpkgs"
- ],
- "rust-analyzer-src": []
- },
- "locked": {
- "lastModified": 1722580276,
- "narHash": "sha256-VaNcSh7n8OaFW/DJsR6Fm23V+EGpSei0DyF71RKB+90=",
- "owner": "nix-community",
- "repo": "fenix",
- "rev": "286f371b3cfeaa5c856c8e6dfb893018e86cc947",
- "type": "github"
- },
- "original": {
- "owner": "nix-community",
- "repo": "fenix",
- "type": "github"
- }
- },
"nixpkgs": {
"locked": {
"lastModified": 1722415718,
@@ -39,7 +18,6 @@
},
"root": {
"inputs": {
- "fenix": "fenix",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix"
}
diff --git a/flake.nix b/flake.nix
index d5b9d3d..361ee02 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,13 +4,8 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
- fenix = {
- url = "github:nix-community/fenix";
- inputs = {
- nixpkgs.follows = "nixpkgs";
- rust-analyzer-src.follows = "";
- };
- };
+ # Inputs below this are optional
+ # `inputs.treefmt-nix.follows = ""`
treefmt-nix = {
url = "github:numtide/treefmt-nix";
@@ -22,7 +17,6 @@
{
self,
nixpkgs,
- fenix,
treefmt-nix,
}:
let
@@ -39,21 +33,49 @@
treefmtFor = forAllSystems (system: treefmt-nix.lib.evalModule nixpkgsFor.${system} ./treefmt.nix);
in
{
- checks = forAllSystems (system: {
- treefmt = treefmtFor.${system}.config.build.check self;
- });
+ checks = forAllSystems (
+ system:
+ let
+ pkgs = nixpkgsFor.${system};
+ in
+ {
+ clippy-sarif = pkgs.stdenv.mkDerivation {
+ name = "check-clippy-sarif";
+ inherit (self.packages.${system}.nixpkgs-tracker-bot) src cargoDeps;
+
+ nativeBuildInputs = with pkgs; [
+ cargo
+ clippy
+ clippy-sarif
+ pkg-config
+ rustPlatform.cargoSetupHook
+ rustc
+ sarif-fmt
+ ];
+
+ buildInputs = [ pkgs.openssl ];
+
+ buildPhase = ''
+ cargo clippy \
+ --all-features \
+ --all-targets \
+ --tests \
+ --message-format=json \
+ | clippy-sarif | tee $out | sarif-fmt
+ '';
+ };
+
+ treefmt = treefmtFor.${system}.config.build.check self;
+ }
+ );
devShells = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
- inputsFrom = [ self.packages.${system}.nixpkgs-tracker-bot ];
in
{
default = pkgs.mkShell {
- inherit inputsFrom;
- RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}";
-
packages = [
pkgs.clippy
pkgs.rustfmt
@@ -61,14 +83,11 @@
self.formatter.${system}
];
- };
- ci = pkgs.mkShell {
- inherit inputsFrom;
- packages = [
- pkgs.clippy
- pkgs.rustfmt
- ];
+ inputsFrom = [ self.packages.${system}.nixpkgs-tracker-bot ];
+ env = {
+ RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}";
+ };
};
}
);
@@ -81,37 +100,21 @@
system:
let
pkgs = nixpkgsFor.${system};
- packages = self.packages.${system};
-
- mkStaticWith = pkgs.callPackage ./nix/static.nix {
- inherit (packages) nixpkgs-tracker-bot;
- fenix = fenix.packages.${system};
- };
+ packages' = self.packages.${system};
- containerWith =
- nixpkgs-tracker-bot:
- let
- arch = nixpkgs-tracker-bot.stdenv.hostPlatform.ubootArch;
- in
- pkgs.dockerTools.buildLayeredImage {
- name = "nixpkgs-tracker-bot";
- tag = "latest-${arch}";
- config.Cmd = [ (lib.getExe nixpkgs-tracker-bot) ];
- architecture = arch;
- };
+ staticWith = pkgs.callPackage ./nix/static.nix { };
+ containerize = pkgs.callPackage ./nix/containerize.nix { };
in
{
- nixpkgs-tracker-bot = pkgs.callPackage ./nix/package.nix {
- version = self.shortRev or self.dirtyShortRev or "unknown";
- };
+ nixpkgs-tracker-bot = pkgs.callPackage ./nix/package.nix { };
- default = packages.nixpkgs-tracker-bot;
+ default = packages'.nixpkgs-tracker-bot;
- static-x86_64 = mkStaticWith { arch = "x86_64"; };
- static-arm64 = mkStaticWith { arch = "aarch64"; };
+ static-x86_64 = staticWith { arch = "x86_64"; };
+ static-arm64 = staticWith { arch = "aarch64"; };
- container-x86_64 = containerWith packages.static-x86_64;
- container-arm64 = containerWith packages.static-arm64;
+ container-amd64 = containerize packages'.static-x86_64;
+ container-arm64 = containerize packages'.static-arm64;
}
);
};
diff --git a/nix/containerize.nix b/nix/containerize.nix
new file mode 100644
index 0000000..d83b998
--- /dev/null
+++ b/nix/containerize.nix
@@ -0,0 +1,16 @@
+{ lib, dockerTools }:
+let
+ containerize =
+ nixpkgs-tracker-bot:
+ let
+ inherit (nixpkgs-tracker-bot.passthru) crossPkgs;
+ architecture = crossPkgs.go.GOARCH;
+ in
+ dockerTools.buildLayeredImage {
+ name = "nixpkgs-tracker-bot";
+ tag = "latest-${architecture}";
+ config.Cmd = [ (lib.getExe nixpkgs-tracker-bot) ];
+ inherit architecture;
+ };
+in
+containerize
diff --git a/nix/package.nix b/nix/package.nix
index 261e785..b216242 100644
--- a/nix/package.nix
+++ b/nix/package.nix
@@ -3,13 +3,12 @@
rustPlatform,
openssl,
pkg-config,
- version,
lto ? true,
optimizeSize ? false,
}:
rustPlatform.buildRustPackage {
pname = "nixpkgs-tracker-bot";
- inherit version;
+ inherit ((lib.importTOML ../Cargo.toml).workspace.package) version;
src = lib.fileset.toSource {
root = ../.;
diff --git a/nix/static.nix b/nix/static.nix
index 86a1cc3..8def285 100644
--- a/nix/static.nix
+++ b/nix/static.nix
@@ -1,45 +1,16 @@
-{
- lib,
- fenix,
- pkgsCross,
- nixpkgs-tracker-bot,
-}:
+{ pkgsCross }:
let
crossPkgsFor = with pkgsCross; {
x86_64 = musl64.pkgsStatic;
aarch64 = aarch64-multiplatform;
};
-
- rustcTargetFor = lib.mapAttrs (lib.const (
- pkgs: pkgs.stdenv.hostPlatform.rust.rustcTarget
- )) crossPkgsFor;
- rustStdFor = lib.mapAttrs (lib.const (
- rustcTarget: fenix.targets.${rustcTarget}.stable.rust-std
- )) rustcTargetFor;
-
- toolchain =
- with fenix;
- combine (
- [
- stable.cargo
- stable.rustc
- ]
- ++ lib.attrValues rustStdFor
- );
-
- crossPlatformFor = lib.mapAttrs (lib.const (
- pkgs:
- pkgs.makeRustPlatform (
- lib.genAttrs [
- "cargo"
- "rustc"
- ] (lib.const toolchain)
- )
- )) crossPkgsFor;
in
{ arch }:
-nixpkgs-tracker-bot.override {
- rustPlatform = crossPlatformFor.${arch};
- inherit (crossPkgsFor.${arch}) openssl;
- optimizeSize = true;
-}
+let
+ crossPkgs = crossPkgsFor.${arch};
+in
+(crossPkgs.callPackage ./package.nix { optimizeSize = true; }).overrideAttrs (old: {
+ passthru = old.passthru or { } // {
+ inherit crossPkgs;
+ };
+})
diff --git a/treefmt.nix b/treefmt.nix
index f3dcaac..81102bc 100644
--- a/treefmt.nix
+++ b/treefmt.nix
@@ -1,11 +1,10 @@
{
projectRootFile = ".git/config";
- # TODO: add actionlint
- # https://github.com/numtide/treefmt-nix/pull/146
programs = {
+ actionlint.enable = true;
deadnix.enable = true;
- nixfmt-rfc-style.enable = true;
+ nixfmt.enable = true;
rustfmt.enable = true;
statix.enable = true;
};