summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2019-07-11 15:06:39 +0200
committerPietro Albini <pietro@pietroalbini.org>2019-07-13 21:13:52 +0200
commit6c69a5ee75f18ecaa8b5cb7a320ed2cde94fb711 (patch)
tree45f7554f256f10fa1f25147877eeb7c5b07718e5 /src
parent14a42ebabfd56eb50447d8d8c8d4e2b1235cf1c7 (diff)
add the add-person subcommand
Diffstat (limited to 'src')
-rw-r--r--src/github.rs50
-rw-r--r--src/main.rs59
2 files changed, 106 insertions, 3 deletions
diff --git a/src/github.rs b/src/github.rs
new file mode 100644
index 0000000..9a62994
--- /dev/null
+++ b/src/github.rs
@@ -0,0 +1,50 @@
+use failure::{Error, ResultExt};
+use reqwest::header::{self, HeaderValue};
+use reqwest::{Client, Method, RequestBuilder};
+use std::borrow::Cow;
+
+static API_BASE: &str = "https://api.github.com/";
+static TOKEN_VAR: &str = "GITHUB_TOKEN";
+
+#[derive(serde::Deserialize)]
+pub(crate) struct User {
+ pub(crate) login: String,
+ pub(crate) name: Option<String>,
+ pub(crate) email: Option<String>,
+}
+
+pub(crate) struct GitHubApi {
+ http: Client,
+ token: String,
+}
+
+impl GitHubApi {
+ pub(crate) fn new() -> Result<Self, Error> {
+ let token = std::env::var(TOKEN_VAR)
+ .with_context(|_| format!("missing environment variable {}", TOKEN_VAR))?;
+ Ok(GitHubApi {
+ http: Client::new(),
+ token: token.to_string(),
+ })
+ }
+
+ fn prepare(&self, method: Method, url: &str) -> Result<RequestBuilder, Error> {
+ let url = if url.starts_with("https://") {
+ Cow::Borrowed(url)
+ } else {
+ Cow::Owned(format!("{}{}", API_BASE, url))
+ };
+ Ok(self.http.request(method, url.as_ref()).header(
+ header::AUTHORIZATION,
+ HeaderValue::from_str(&format!("token {}", self.token))?,
+ ))
+ }
+
+ pub(crate) fn user(&self, login: &str) -> Result<User, Error> {
+ Ok(self
+ .prepare(Method::GET, &format!("users/{}", login))?
+ .send()?
+ .error_for_status()?
+ .json()?)
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 1b45257..c47f270 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,12 +3,14 @@
mod data;
#[macro_use]
mod permissions;
+mod github;
mod schema;
mod static_api;
mod validate;
use crate::data::Data;
use failure::{err_msg, Error};
+use log::{error, info, warn};
use std::path::PathBuf;
use structopt::StructOpt;
@@ -17,6 +19,11 @@ use structopt::StructOpt;
enum Cli {
#[structopt(name = "check", help = "check if the configuration is correct")]
Check,
+ #[structopt(
+ name = "add-person",
+ help = "add a new person from their GitHub profile"
+ )]
+ AddPerson { github_name: String },
#[structopt(name = "static-api", help = "generate the static API")]
StaticApi { dest: String },
#[structopt(name = "dump-team", help = "print the members of a team")]
@@ -36,11 +43,19 @@ enum Cli {
}
fn main() {
- env_logger::init();
+ let mut env = env_logger::Builder::new();
+ env.default_format_timestamp(false);
+ env.default_format_module_path(false);
+ env.filter_module("rust_team", log::LevelFilter::Info);
+ if let Ok(content) = std::env::var("RUST_LOG") {
+ env.parse(&content);
+ }
+ env.init();
+
if let Err(e) = run() {
- eprintln!("error: {}", e);
+ error!("{}", e);
for e in e.iter_causes() {
- eprintln!(" cause: {}", e);
+ error!("cause: {}", e);
}
std::process::exit(1);
}
@@ -53,6 +68,44 @@ fn run() -> Result<(), Error> {
Cli::Check => {
crate::validate::validate(&data)?;
}
+ Cli::AddPerson { ref github_name } => {
+ #[derive(serde::Serialize)]
+ struct PersonToAdd<'a> {
+ name: &'a str,
+ github: &'a str,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ email: Option<&'a str>,
+ }
+
+ let github = github::GitHubApi::new()?;
+ let user = github.user(github_name)?;
+ let github_name = user.login;
+
+ if data.person(&github_name).is_some() {
+ failure::bail!("person already in the repo: {}", github_name);
+ }
+
+ let file = format!("people/{}.toml", github_name);
+ std::fs::write(
+ &file,
+ toml::to_string_pretty(&PersonToAdd {
+ name: user.name.as_ref().map(|n| n.as_str()).unwrap_or_else(|| {
+ warn!(
+ "the person is missing the name on GitHub, defaulting to the username"
+ );
+ github_name.as_str()
+ }),
+ github: &github_name,
+ email: user.email.as_ref().map(|e| e.as_str()).or_else(|| {
+ warn!("the person is missing the email on GitHub, leaving the field empty");
+ None
+ }),
+ })?
+ .as_bytes(),
+ )?;
+
+ info!("written data to {}", file);
+ }
Cli::StaticApi { ref dest } => {
let dest = PathBuf::from(dest);
let generator = crate::static_api::Generator::new(&dest, &data)?;