mirror of
https://github.com/DeterminateSystems/flake-checker.git
synced 2024-10-05 18:27:42 +03:00
Add clean and dirty tests
This commit is contained in:
parent
145fd124a4
commit
e13713b477
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -18,6 +18,16 @@ jobs:
|
||||
- name: Check Rust formatting
|
||||
run: nix develop -c check-rustfmt
|
||||
|
||||
rust-tests:
|
||||
name: Test Rust
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@v4
|
||||
- name: cargo test
|
||||
run: nix develop -c cargo test
|
||||
|
||||
check-flake-dirty:
|
||||
name: Check flake.lock test (dirty 😈)
|
||||
runs-on: ubuntu-22.04
|
||||
@ -27,7 +37,7 @@ jobs:
|
||||
uses: DeterminateSystems/nix-installer-action@v4
|
||||
- name: Check flake.lock
|
||||
run: |
|
||||
nix develop -c cargo run -- ./flake.dirty.lock
|
||||
nix develop -c cargo run -- ./tests/flake.dirty.0.lock
|
||||
|
||||
check-flake-clean:
|
||||
name: Check flake.lock test (clean 👼)
|
||||
@ -50,4 +60,4 @@ jobs:
|
||||
uses: DeterminateSystems/nix-installer-action@v2
|
||||
- name: Check flake.lock
|
||||
run: |
|
||||
nix develop -c cargo run -- ./flake.dirty.lock --fail-mode
|
||||
nix develop -c cargo run -- --fail-mode ./tests/flake.dirty.0.lock
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -204,7 +204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flake-checker"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
95
src/flake.rs
95
src/flake.rs
@ -1,8 +1,11 @@
|
||||
#![allow(dead_code)]
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::issue::{Issue, IssueKind};
|
||||
use crate::FlakeCheckerError;
|
||||
|
||||
use chrono::{Duration, Utc};
|
||||
use serde::de::{self, Deserializer, MapAccess, Visitor};
|
||||
@ -24,18 +27,29 @@ pub const ALLOWED_REFS: &[&str] = &[
|
||||
];
|
||||
pub const MAX_DAYS: i64 = 30;
|
||||
|
||||
pub fn check_flake_lock(
|
||||
flake_lock: &FlakeLock,
|
||||
check_supported: bool,
|
||||
check_outdated: bool,
|
||||
check_owner: bool,
|
||||
) -> Vec<Issue> {
|
||||
pub struct FlakeCheckConfig {
|
||||
pub check_supported: bool,
|
||||
pub check_outdated: bool,
|
||||
pub check_owner: bool,
|
||||
}
|
||||
|
||||
impl Default for FlakeCheckConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
check_supported: true,
|
||||
check_outdated: true,
|
||||
check_owner: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_flake_lock(flake_lock: &FlakeLock, config: &FlakeCheckConfig) -> Vec<Issue> {
|
||||
let mut issues = vec![];
|
||||
|
||||
for (name, dep) in flake_lock.nixpkgs_deps() {
|
||||
if let Node::Repo(repo) = dep {
|
||||
// Check if not explicitly supported
|
||||
if check_supported {
|
||||
if config.check_supported {
|
||||
if let Some(ref git_ref) = repo.original.git_ref {
|
||||
if !ALLOWED_REFS.contains(&git_ref.as_str()) {
|
||||
issues.push(Issue {
|
||||
@ -51,7 +65,7 @@ pub fn check_flake_lock(
|
||||
}
|
||||
|
||||
// Check if outdated
|
||||
if check_outdated {
|
||||
if config.check_outdated {
|
||||
let now_timestamp = Utc::now().timestamp();
|
||||
let diff = now_timestamp - repo.locked.last_modified;
|
||||
let num_days_old = Duration::seconds(diff).num_days();
|
||||
@ -69,7 +83,7 @@ pub fn check_flake_lock(
|
||||
}
|
||||
|
||||
// Check that the GitHub owner is NixOS
|
||||
if check_owner {
|
||||
if config.check_owner {
|
||||
let owner = repo.original.owner;
|
||||
if owner.to_lowercase() != "nixos" {
|
||||
issues.push(Issue {
|
||||
@ -94,6 +108,14 @@ pub struct FlakeLock {
|
||||
version: usize,
|
||||
}
|
||||
|
||||
impl FlakeLock {
|
||||
pub fn new(path: &PathBuf) -> Result<Self, FlakeCheckerError> {
|
||||
let flake_lock_file = read_to_string(path)?;
|
||||
let flake_lock: FlakeLock = serde_json::from_str(&flake_lock_file)?;
|
||||
Ok(flake_lock)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FlakeLock {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
@ -252,3 +274,58 @@ struct RepoOriginal {
|
||||
#[serde(alias = "ref")]
|
||||
git_ref: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{check_flake_lock, FlakeCheckConfig, FlakeLock, issue::{Issue, IssueKind}};
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_clean_flake_locks() {
|
||||
for n in vec![0] {
|
||||
let path = format!("tests/flake.clean.{n}.lock");
|
||||
let flake_lock = FlakeLock::new(&path.into()).expect("couldn't create flake.lock");
|
||||
let config = FlakeCheckConfig {
|
||||
check_outdated: false,
|
||||
..Default::default()
|
||||
};
|
||||
let issues = check_flake_lock(&flake_lock, &config);
|
||||
assert!(issues.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirty_flake_locks() {
|
||||
let cases: Vec<(&str, Vec<Issue>)> = vec![
|
||||
("flake.dirty.0.lock", vec![
|
||||
Issue {
|
||||
dependency: String::from("nixpkgs"),
|
||||
kind: IssueKind::Disallowed,
|
||||
details: json!({
|
||||
"input": String::from("nixpkgs"),
|
||||
"ref": String::from("this-should-fail"),
|
||||
}),
|
||||
},
|
||||
Issue {
|
||||
dependency: String::from("nixpkgs"),
|
||||
kind: IssueKind::NonUpstream,
|
||||
details: json!({
|
||||
"input": String::from("nixpkgs"),
|
||||
"owner": String::from("bitcoin-miner-org"),
|
||||
}),
|
||||
},
|
||||
]),
|
||||
];
|
||||
|
||||
for (file, expected_issues) in cases {
|
||||
let path = format!("tests/{file}");
|
||||
let flake_lock = FlakeLock::new(&path.into()).expect("couldn't create flake.lock");
|
||||
let config = FlakeCheckConfig {
|
||||
check_outdated: false,
|
||||
..Default::default()
|
||||
};
|
||||
let issues = check_flake_lock(&flake_lock, &config);
|
||||
assert_eq!(issues, expected_issues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
pub struct Issue {
|
||||
pub dependency: String,
|
||||
pub kind: IssueKind,
|
||||
pub details: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
pub enum IssueKind {
|
||||
#[serde(rename = "disallowed")]
|
||||
Disallowed,
|
||||
|
14
src/main.rs
14
src/main.rs
@ -5,10 +5,9 @@ mod summary;
|
||||
pub mod telemetry;
|
||||
|
||||
pub use error::FlakeCheckerError;
|
||||
pub use flake::{check_flake_lock, FlakeLock};
|
||||
pub use flake::{check_flake_lock, FlakeCheckConfig, FlakeLock};
|
||||
pub use summary::Summary;
|
||||
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
@ -86,10 +85,15 @@ fn main() -> Result<ExitCode, FlakeCheckerError> {
|
||||
}
|
||||
}
|
||||
|
||||
let flake_lock_file = read_to_string(flake_lock_path)?;
|
||||
let flake_lock: FlakeLock = serde_json::from_str(&flake_lock_file)?;
|
||||
let flake_lock = FlakeLock::new(&flake_lock_path)?;
|
||||
|
||||
let issues = check_flake_lock(&flake_lock, check_supported, check_outdated, check_owner);
|
||||
let flake_check_config = FlakeCheckConfig {
|
||||
check_supported,
|
||||
check_outdated,
|
||||
check_owner,
|
||||
};
|
||||
|
||||
let issues = check_flake_lock(&flake_lock, &flake_check_config);
|
||||
|
||||
if !no_telemetry {
|
||||
telemetry::TelemetryReport::make_and_send(&issues);
|
||||
|
154
tests/flake.clean.0.lock
Normal file
154
tests/flake.clean.0.lock
Normal file
@ -0,0 +1,154 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1684468982,
|
||||
"narHash": "sha256-EoC1N5sFdmjuAP3UOkyQujSOT6EdcXTnRw8hPjJkEgc=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "99de890b6ef4b4aab031582125b6056b792a4a30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "flake-utils",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1686960236,
|
||||
"narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "04af42f3b31dba0ef742d254456dc4c14eedac86",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"crane",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"crane",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1683080331,
|
||||
"narHash": "sha256-nGDvJ1DAxZIwdn6ww8IFwzoHb2rqBP4wv/65Wt5vflk=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "d59c3fa0cba8336e115b376c2d9e91053aa59e56",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1684808436,
|
||||
"narHash": "sha256-WG5LgB1+Oguj4H4Bpqr5GoLSc382LyGlaToiOw5xhwA=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "a227d4571dd1f948138a40ea8b0d0c413eefb44b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
Loading…
Reference in New Issue
Block a user