Repository: TeXitoi/structopt (Rust)

Issue:
Inherit no_version for enum variants
In my non-Cargo build environment I end up with a lot of noise from no_version attributes. For subcommands, if the outer enum is no_version I think I shouldn't need to specify no_version as well for each of the command variants.

Currently `derive(StructOpt)` produces an error if any of the no_version attrs here are removed:

```rust
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(no_version)]
enum Show {
    #[structopt(no_version)]
    Stats,
    #[structopt(no_version)]
    Capacity,
}
```


Discussion:
I agree. @TeXitoi what do you think? 

By the way, @dtolnay , I wonder what non-cargo environment you're working with?
By the way, it looks like a bug - `#[structopt(no_verison)]` should not (and need not to) be usable on enum variants, only on top of the struct or enum
That's because the enum can be transformed to a `clap::App`, and that each enum is a subcommand that also generate a `clap::App`.
I'll see if we can catch this situation. I also think that `no_version` should be propagated down to subcommands - if we don't want version for the program itself why would we wan a version for subcommands?
@TeXitoi so what do you think about it? It can be implemented almost for no effort.
Then OK for it



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ed2a17f1..0e8da55f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# [Upcoming]
+
+* You don't have to apply `#[no_version]` to every `enum` variant anymore.
+  Just annotate the `enum` and the setting will be propagated down
+  ([#242](https://github.com/TeXitoi/structopt/issues/242)).
+
 # v0.3.7 (2019-12-28)
 
 Nothing's new. Just re-release of `v0.3.6` due to
diff --git a/structopt-derive/src/attrs.rs b/structopt-derive/src/attrs.rs
index ce684a24..1233b55d 100644
--- a/structopt-derive/src/attrs.rs
+++ b/structopt-derive/src/attrs.rs
@@ -215,9 +215,15 @@ impl Attrs {
     fn new(
         default_span: Span,
         name: Name,
+        parent_attrs: Option<&Attrs>,
         casing: Sp<CasingStyle>,
         env_casing: Sp<CasingStyle>,
     ) -> Self {
+        let no_version = parent_attrs
+            .as_ref()
+            .map(|attrs| attrs.no_version.clone())
+            .unwrap_or(None);
+
         Self {
             name,
             casing,
@@ -228,7 +234,7 @@ impl Attrs {
             about: None,
             author: None,
             version: None,
-            no_version: None,
+            no_version,
             verbatim_doc_comment: None,
 
             has_custom_parser: false,
@@ -347,10 +353,11 @@ impl Attrs {
         span: Span,
         attrs: &[Attribute],
         name: Name,
+        parent_attrs: Option<&Attrs>,
         argument_casing: Sp<CasingStyle>,
         env_casing: Sp<CasingStyle>,
     ) -> Self {
-        let mut res = Self::new(span, name, argument_casing, env_casing);
+        let mut res = Self::new(span, name, parent_attrs, argument_casing, env_casing);
         res.push_attrs(attrs);
         res.push_doc_comment(attrs, "about");
 
@@ -370,6 +377,7 @@ impl Attrs {
 
     pub fn from_field(
         field: &syn::Field,
+        parent_attrs: Option<&Attrs>,
         struct_casing: Sp<CasingStyle>,
         env_casing: Sp<CasingStyle>,
     ) -> Self {
@@ -377,6 +385,7 @@ impl Attrs {
         let mut res = Self::new(
             field.span(),
             Name::Derived(name.clone()),
+            parent_attrs,
             struct_casing,
             env_casing,
         );
diff --git a/structopt-derive/src/lib.rs b/structopt-derive/src/lib.rs
index 87eaf1f0..0975569a 100644
--- a/structopt-derive/src/lib.rs
+++ b/structopt-derive/src/lib.rs
@@ -66,6 +66,7 @@ fn gen_augmentation(
     let mut subcmds = fields.iter().filter_map(|field| {
         let attrs = Attrs::from_field(
             field,
+            Some(parent_attribute),
             parent_attribute.casing(),
             parent_attribute.env_casing(),
         );
@@ -109,6 +110,7 @@ fn gen_augmentation(
     let args = fields.iter().filter_map(|field| {
         let attrs = Attrs::from_field(
             field,
+            Some(parent_attribute),
             parent_attribute.casing(),
             parent_attribute.env_casing(),
         );
@@ -235,6 +237,7 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
     let fields = fields.iter().map(|field| {
         let attrs = Attrs::from_field(
             field,
+            Some(parent_attribute),
             parent_attribute.casing(),
             parent_attribute.env_casing(),
         );
@@ -380,6 +383,7 @@ fn gen_clap(attrs: &[Attribute]) -> GenOutput {
         Span::call_site(),
         attrs,
         Name::Assigned(LitStr::new(&name, Span::call_site())),
+        None,
         Sp::call_site(DEFAULT_CASING),
         Sp::call_site(DEFAULT_ENV_CASING),
     );
@@ -449,6 +453,7 @@ fn gen_augment_clap_enum(
             variant.span(),
             &variant.attrs,
             Name::Derived(variant.ident.clone()),
+            Some(parent_attribute),
             parent_attribute.casing(),
             parent_attribute.env_casing(),
         );
@@ -520,6 +525,7 @@ fn gen_from_subcommand(
             variant.span(),
             &variant.attrs,
             Name::Derived(variant.ident.clone()),
+            Some(parent_attribute),
             parent_attribute.casing(),
             parent_attribute.env_casing(),
         );


Test patch:
diff --git a/tests/author_version_about.rs b/tests/author_version_about.rs
index 0c4a4fbb..0f1c8b57 100644
--- a/tests/author_version_about.rs
+++ b/tests/author_version_about.rs
@@ -44,3 +44,15 @@ fn explicit_version_not_str() {
     let output = get_long_help::<Opt>();
     assert!(output.contains("custom version"));
 }
+
+#[test]
+fn no_version_gets_propagated() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(no_version)]
+    enum Action {
+        Move,
+    }
+
+    let output = get_subcommand_long_help::<Action>("move");
+    assert_eq!(output.lines().next(), Some("test-move "));
+}