Submit telemetry about how many of each issue we identified

This commit is contained in:
Graham Christensen 2023-05-24 10:59:36 -04:00 committed by Graham Christensen
parent aac5b8103c
commit 5efcd4d923
6 changed files with 857 additions and 30 deletions

751
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,11 @@ edition = "2021"
[dependencies]
chrono = "0.4.24"
clap = { version = "4.2.7", features = ["derive"] }
clap = { version = "4.2.7", features = ["derive", "env"] }
handlebars = "4.3.7"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"
thiserror = "1.0.40"
sha2 = "0.10.6"
is_ci = "1.1.1"
reqwest = { version = "0.11.18", default-features = false, features = [ "blocking", "rustls-tls-native-roots" ]}

View File

@ -11,11 +11,35 @@ nix build
Currently performs two checks:
* Checks that any explicit Nixpkgs Git refs are in this list:
* `nixos-22.11`
* `nixos-22.11-small`
* `nixos-unstable`
* `nixos-unstable-small`
* `nixpkgs-22.11-darwin`
* `nixpkgs-unstable`
* Checks that any Nixpkgs dependencies are less than 30 days old
- Checks that any explicit Nixpkgs Git refs are in this list:
- `nixos-22.11`
- `nixos-22.11-small`
- `nixos-unstable`
- `nixos-unstable-small`
- `nixpkgs-22.11-darwin`
- `nixpkgs-unstable`
- Checks that any Nixpkgs dependencies are less than 30 days old
### Telemetry
The goal of the Determinate Flake Checker is to help teams stay on recent and supported versions of Nixpkgs.
The flake checker collects a little bit of telemetry information to help us make that true.
Here is a table of the [telemetry data we collect][diagnosticdata]:
| Field | Use |
| -------------- | ------------------------------------------------------------------------------------------------------ |
| `distinct_id` | An opaque string which represents your project, by sha256 hashing repository and organization details. |
| `version` | The version of the Determinate Flake Checker. |
| `is_ci` | Whether the installer is being used in CI (e.g. GitHub Actions). |
| `disallowed` | The number of inputs using unsupported branches of Nixpkgs. |
| `outdated` | The number of inputs using outdated versions of Nixpkgs. |
| `non_upstream` | The number of inputs using forks of Nixpkgs. |
To disable diagnostic reporting, set the diagnostics URL to an empty string by passing `--no-telemetry` or setting `FLAKE_CHECKER_NO_TELEMETRY=true`.
You can read the full privacy policy for [Determinate Systems][detsys], the creators of the Determinate Nix Installer, [here][privacy].
[detsys]: https://determinate.systems/
[diagnosticdata]: https://github.com/DeterminateSystems/nix-flake-checker/blob/main/src/telemetry.rs#L29-L43
[privacy]: https://determinate.systems/privacy

View File

@ -3,6 +3,7 @@ use serde::Serialize;
mod error;
mod flake;
mod summary;
pub mod telemetry;
pub use error::FlakeCheckerError;
pub use flake::FlakeLock;
@ -27,7 +28,7 @@ pub struct Issue {
details: serde_json::Value,
}
#[derive(Serialize)]
#[derive(Serialize, PartialEq)]
enum IssueKind {
#[serde(rename = "disallowed")]
Disallowed,

View File

@ -1,6 +1,6 @@
extern crate flake_checker;
use flake_checker::{FlakeCheckerError, FlakeLock, Summary};
use flake_checker::{telemetry, FlakeCheckerError, FlakeLock, Summary};
use std::fs::read_to_string;
use std::path::PathBuf;
@ -11,16 +11,33 @@ use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
/// Send aggregate sums of each issue type,
/// see: https://github.com/determinateSystems/flake-checker
#[clap(
long,
env = "NIX_FLAKE_CHECKER_NO_TELEMETRY",
default_value = "false"
)]
no_telemetry: bool,
/// The path to the flake.lock file to check.
#[clap(default_value = "flake.lock")]
flake_lock_path: PathBuf,
}
fn main() -> Result<(), FlakeCheckerError> {
let Cli { flake_lock_path } = Cli::parse();
let Cli {
flake_lock_path,
no_telemetry,
} = Cli::parse();
let flake_lock_file = read_to_string(flake_lock_path)?;
let flake_lock: FlakeLock = serde_json::from_str(&flake_lock_file)?;
let issues = flake_lock.check();
if !no_telemetry {
telemetry::TelemetryReport::make_and_send(&issues);
}
let summary = Summary { issues };
summary.generate_markdown()?;

67
src/telemetry.rs Normal file
View File

@ -0,0 +1,67 @@
use std::env;
use is_ci;
use sha2::{Digest, Sha256};
const TELEMETRY_ENDPOINT: &str = "https://install.determinate.systems/flake-checker/telemetry";
/// A telemetry report to identify trends in outdated locks against nixpkgs
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct TelemetryReport {
pub distinct_id: String,
pub version: String,
pub is_ci: bool,
pub disallowed: usize,
pub outdated: usize,
pub non_upstream: usize,
}
impl TelemetryReport {
pub fn new(issues: &[crate::Issue]) -> Result<TelemetryReport, env::VarError> {
Ok(TelemetryReport {
distinct_id: calculate_opaque_id()?,
version: env!("CARGO_PKG_VERSION").to_string(),
is_ci: is_ci::cached(),
disallowed: issues
.iter()
.filter(|issue| issue.kind == crate::IssueKind::Disallowed)
.count(),
outdated: issues
.iter()
.filter(|issue| issue.kind == crate::IssueKind::Outdated)
.count(),
non_upstream: issues
.iter()
.filter(|issue| issue.kind == crate::IssueKind::NonUpstream)
.count(),
})
}
pub fn make_and_send(issues: &[crate::Issue]) {
if let Ok(report) = TelemetryReport::new(issues) {
if let Ok(serialized) = serde_json::to_string_pretty(&report) {
let _ = reqwest::blocking::Client::new()
.post(TELEMETRY_ENDPOINT)
.body(serialized)
.header("Content-Type", "application/json")
.timeout(std::time::Duration::from_millis(3000))
.send();
}
}
}
}
fn calculate_opaque_id() -> Result<String, env::VarError> {
let mut hasher = Sha256::new();
hasher.update(env::var("GITHUB_REPOSITORY")?);
hasher.update(env::var("GITHUB_REPOSITORY_ID")?);
hasher.update(env::var("GITHUB_REPOSITORY_OWNER")?);
hasher.update(env::var("GITHUB_REPOSITORY_OWNER_ID")?);
let result = hasher.finalize();
Ok(format!("{:x}", result))
}