issue_macros/
lib.rs

1use darling::FromMeta;
2use lazy_static::lazy_static;
3use lib::{Level, Mode};
4use proc_macro::TokenStream;
5use proc_macro_error::{emit_error, emit_warning, proc_macro_error};
6use syn::{parse_macro_input, spanned::Spanned, AttributeArgs};
7
8#[cfg(not(debug_assertions))]
9lazy_static! {
10    static ref MODE: Mode = lib::get_mode().unwrap_or(Mode::Noop);
11}
12
13#[cfg(debug_assertions)]
14lazy_static! {
15    static ref MODE: Mode = lib::get_mode().unwrap_or(Mode::Emit(Level::Warn));
16}
17
18/// Fetches the issue from Github and emits a warning or error if it is closed depending on the
19/// `ISSUE_HARD_FAIL` environment variable.
20#[proc_macro_error]
21#[proc_macro_attribute]
22pub fn track(args: TokenStream, input: TokenStream) -> TokenStream {
23    let attr_args = parse_macro_input!(args as AttributeArgs);
24
25    let issue: lib::Issue = match Issue::from_list(&attr_args) {
26        Ok(v) => v.into(),
27        Err(e) => {
28            return TokenStream::from(e.write_errors());
29        }
30    };
31
32    match *MODE {
33        Mode::Noop => (),
34        Mode::Pipe => println!(
35            "{}",
36            serde_json::to_string(&issue).expect("serializing issue")
37        ),
38        Mode::Emit(Level::Warn) => match issue.is_closed() {
39            Err(e) => {
40                emit_warning!(
41                    attr_args[0].span(),
42                    "unable to access {}\n  {}",
43                    issue.url,
44                    e
45                )
46            }
47            Ok(true) => {
48                emit_warning!(attr_args[0].span(), "issue {} has been closed", issue.url)
49            }
50            _ => (),
51        },
52        Mode::Emit(Level::Error) => match issue.is_closed() {
53            Err(e) => {
54                emit_error!(
55                    attr_args[0].span(),
56                    "unable to access {}\n  {}",
57                    issue.url,
58                    e
59                )
60            }
61            Ok(true) => {
62                emit_error!(attr_args[0].span(), "issue {} has been closed", issue.url)
63            }
64            _ => (),
65        },
66    }
67    input
68}
69
70#[derive(Default, Debug, FromMeta, serde::Serialize)]
71#[darling(default)]
72struct Issue {
73    pub url: String,
74}
75
76impl From<Issue> for lib::Issue {
77    fn from(issue: Issue) -> Self {
78        lib::Issue { url: issue.url }
79    }
80}