Skip to content

Commit

Permalink
feat(cli): add optional field for scope (#368)
Browse files Browse the repository at this point in the history
* feat(cli): add optional field for scope

Signed-off-by: KeisukeYamashita <[email protected]>

* feat(web): add optional scopes example

Signed-off-by: KeisukeYamashita <[email protected]>

---------

Signed-off-by: KeisukeYamashita <[email protected]>
  • Loading branch information
KeisukeYamashita authored Oct 8, 2024
1 parent 5ba81cf commit f85ce98
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
56 changes: 55 additions & 1 deletion src/rule/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ pub struct Scope {
/// Options represents the options of the rule.
/// If the option is empty, it means that no scope is allowed.
options: Vec<String>,

/// Optional scope.
/// If true, even if the scope is not present, it is allowed.
optional: bool,
}

/// Scope represents the scope rule.
Expand All @@ -37,7 +41,7 @@ impl Rule for Scope {
fn validate(&self, message: &Message) -> Option<Violation> {
match &message.scope {
None => {
if self.options.is_empty() {
if self.options.is_empty() || self.optional {
return None;
}
}
Expand All @@ -64,6 +68,7 @@ impl Default for Scope {
fn default() -> Self {
Self {
level: Some(Self::LEVEL),
optional: false,
options: vec![],
}
}
Expand Down Expand Up @@ -235,5 +240,54 @@ mod tests {
"scope invalid is not allowed. Only [\"api\", \"web\"] are allowed".to_string()
);
}

#[test]
fn test_optional_scope_with_non_empty_scope() {
let rule = Scope {
options: vec!["api".to_string(), "web".to_string()],
optional: true,
..Default::default()
};

let message = Message {
body: None,
description: None,
footers: None,
r#type: Some("feat".to_string()),
raw: "feat(invalid): broadcast $destroy event on scope destruction".to_string(),
scope: Some("invalid".to_string()),
subject: None,
};

let violation = rule.validate(&message);
assert!(violation.is_some());
assert_eq!(violation.clone().unwrap().level, Level::Error);
assert_eq!(
violation.unwrap().message,
"scope invalid is not allowed. Only [\"api\", \"web\"] are allowed".to_string()
);
}

#[test]
fn test_optional_scope_with_empty_scope() {
let rule = Scope {
options: vec!["api".to_string(), "web".to_string()],
optional: true,
..Default::default()
};

let message = Message {
body: None,
description: None,
footers: None,
r#type: Some("feat".to_string()),
raw: "feat: broadcast $destroy event on scope destruction".to_string(),
scope: None,
subject: None,
};

let violation = rule.validate(&message);
assert!(violation.is_none());
}
}
}
17 changes: 16 additions & 1 deletion web/src/content/docs/rules/scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ title: Scope
description: Allowlist for scopes
---

* Default: `ignore`
* Default:
* Level: `ignore`
* Optional: `false`

In this example, we assumed that you have a project with the following scopes:

Expand Down Expand Up @@ -42,6 +44,19 @@ rules:
- web
```
### Optional scopes `api` and `web`

```yaml
rules:
scope:
level: error
optional: true
options:
- api
```

With this configuration, `feat(api): xxx` and `feat: xxx` are valid commits.

### Disallow all scopes

```yaml
Expand Down

0 comments on commit f85ce98

Please sign in to comment.