Skip to content

Instantly share code, notes, and snippets.

@DJMcNab
Created July 19, 2021 18:16
Show Gist options
  • Select an option

  • Save DJMcNab/dbb89917ab9cc533727cd62488e8ac26 to your computer and use it in GitHub Desktop.

Select an option

Save DJMcNab/dbb89917ab9cc533727cd62488e8ac26 to your computer and use it in GitHub Desktop.
License Checker
[package]
name = "licenses"
version = "0.1.0"
authors = ["Daniel McNab"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
octocrab = "0.9.1"
tokio = { version="1.7.1", features=["rt", "macros", "rt-multi-thread"] }
serde_json = "*"
use std::collections::hash_map::RandomState;
use std::collections::{HashMap, HashSet};
use std::io::Write;
use std::iter::FromIterator;
use octocrab;
fn crab() -> octocrab::Octocrab {
octocrab::Octocrab::builder()
.personal_token("<YOUR TOKEN HERE>".to_string())
.build()
.unwrap()
}
#[tokio::main]
async fn main() {
let first = std::env::args().skip(1).next();
let owner = "bevyengine";
let repo = "bevy";
match first.as_deref() {
Some("download_prs") => {
let mut all_prs = Vec::new();
let mut empty_pages = 0u32;
let mut page = 0u32;
let octocrab = crab();
loop {
let pulls = octocrab
.pulls(owner, repo)
.list()
.state(octocrab::params::State::All)
.page(page)
.per_page(50)
.send()
.await
.unwrap();
let count = (&pulls).into_iter().count();
eprintln!("{}: {}", page, count);
all_prs.extend(pulls);
if count == 0 {
empty_pages += 1;
} else {
empty_pages = 0;
}
if empty_pages > 3 {
break;
}
page += 1;
}
let file = std::fs::File::create("out/bevy_prs.json").unwrap();
serde_json::to_writer_pretty(file, &all_prs).unwrap();
}
Some("download_comments") => {
let mut all_comments = Vec::new();
let mut empty_pages = 0u32;
let mut page = 0u32;
let octocrab = crab();
loop {
let comments = octocrab
.issues(owner, repo)
.list_comments(2373)
.page(page)
.per_page(50)
.send()
.await
.unwrap();
let count = (&comments).into_iter().count();
eprintln!("{}: {}", page, count);
all_comments.extend(comments);
if count == 0 {
empty_pages += 1;
} else {
empty_pages = 0;
}
if empty_pages > 3 {
break;
}
page += 1;
}
let file = std::fs::File::create("out/relicense_comments.json").unwrap();
serde_json::to_writer_pretty(file, &all_comments).unwrap();
}
Some("parse_authors") => {
let thread = std::thread::Builder::new()
.stack_size(100_000_000)
.spawn(|| {
let file = std::fs::read("out/bevy_prs.json").unwrap();
let all_prs: Vec<octocrab::models::pulls::PullRequest> =
serde_json::from_slice(&file).unwrap();
let mut users = HashSet::new();
let co_authors = std::fs::read_to_string("out/co_authors.txt").unwrap();
for co_author in co_authors.lines(){
users.insert(co_author.trim().to_string());
}
for pr in all_prs {
let mut should = /* matches!(pr.state, octocrab::models::IssueState::Open)
|| */ pr.merged_at.is_some();
should |= pr.title.starts_with("[Merged by Bors]");
if should {
users.insert(pr.user.login);
}
}
let mut users = users.into_iter().collect::<Vec<_>>();
users.sort();
let mut output_file = std::fs::File::create("out/uniq_authors.txt").unwrap();
for chunk in users.chunks(45) {
for user in chunk {
writeln!(output_file, "{}", user).unwrap();
}
}
})
.unwrap();
thread.join().unwrap();
}
Some("parse_commenters")=>{
let thread = std::thread::Builder::new()
.stack_size(100_000_000)
.spawn(|| {
let file = std::fs::read("out/relicense_comments.json").unwrap();
let comments: Vec<octocrab::models::issues::Comment> =
serde_json::from_slice(&file).unwrap();
let mut users = HashSet::new();
let known_allright = HashSet::<_, RandomState>::from_iter(["marcusbuffett",
"Incipium",
"mrk-its",
"CAD97",
"anchpop",
"lee-orr",
"cart", // Lol
"termhn",
"GabLotus",
"CGMossa"
]);
let mut sus = HashMap::new();
for cmt in comments {
let text = "I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to choose either at their option";
let text_with_dot_newline = "\nI license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to choose either at their option.";
let body = cmt.body.unwrap();
let body = body.trim();
if body.starts_with(text)|| body.ends_with(text_with_dot_newline) || known_allright.contains(&*cmt.user.login) {
users.insert(cmt.user.login);
}else{
sus.insert(cmt.user.login, cmt.html_url);
}
}
let mut users_vec = users.iter().collect::<Vec<_>>();
users_vec.sort();
let mut output_file = std::fs::File::create("out/agreed.txt").unwrap();
for chunk in users_vec.chunks(45) {
for user in chunk {
writeln!(output_file, "{}", user).unwrap();
}
}
for (user, url) in sus {
if !users.contains(&user){
eprintln!("{}: {}", user, url);
}
}
})
.unwrap();
thread.join().unwrap();
}
Some("diff")=>{
let mut authors = HashSet::new();
for co_author in std::fs::read_to_string("out/uniq_authors.txt").unwrap().lines(){
authors.insert(co_author.trim().to_string());
}
let mut agreer = HashSet::new();
for agreed in std::fs::read_to_string("out/agreed.txt").unwrap().lines(){
agreer.insert(agreed.trim().to_string());
}
let mut output_file = std::fs::File::create("out/diff.txt").unwrap();
let mut out = authors.difference(&agreer).collect::<Vec<_>>();
out.sort();
for diff in out {
writeln!(output_file, "{}", diff).unwrap();
}
}
x => println!(
"Unknown argument {:?}. Valid choices are: download_prs, download_comments, parse_authors, parse_commenters",
x.unwrap_or("")
),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment