Skip to content

Commit

Permalink
feat(cli): generate Json Schema (#389)
Browse files Browse the repository at this point in the history
* feat: add #[cfg_attr(feature = schemars, derive(schemars::JsonSchema))] to all rules & config

* feat: write json-schema/config.json in generate_json_schema

* docs: broken link

* chore: fmt

* fix(cli): remove json output in code

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

* feat(cli): add schema package and generate on release

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

* fix(cli): remove generate_json_schema from cli package

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

---------

Signed-off-by: KeisukeYamashita <[email protected]>
Co-authored-by: KeisukeYamashita <[email protected]>
  • Loading branch information
elcoosp and KeisukeYamashita authored Dec 2, 2024
1 parent d326b49 commit 91bd0a7
Show file tree
Hide file tree
Showing 26 changed files with 131 additions and 42 deletions.
19 changes: 18 additions & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ jobs:
- build
- crate
- docker
- schema
- web
steps:
- uses: actions/download-artifact@v4
Expand All @@ -135,9 +136,25 @@ jobs:
merge-multiple: true
- uses: ncipollo/release-action@v1
with:
artifacts: commitlint/commitlint-*.tar.gz
artifacts: commitlint/commitlint-*.tar.gz,schema.json
generateReleaseNotes: true

schema:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: cargo run --package schema -- --path schema.json
- uses: actions/upload-artifact@v4
with:
name: schema.json
path: schema/schema.json
if-no-files-found: error

web:
runs-on: ubuntu-latest
environment:
Expand Down
45 changes: 28 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["cli"]
members = ["cli", "schema"]
resolver = "2"

[workspace.package]
Expand Down
15 changes: 9 additions & 6 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "commitlint-rs"
name = "cli"
description = "CLI tool to lint commits by Conventional Commits"
documentation.workspace = true
authors.workspace = true
Expand All @@ -13,20 +13,23 @@ edition.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[[bin]]
name = "commitlint"
path = "src/main.rs"

[dependencies]
clap = { version = "4.5.4", features = ["derive", "env", "string"] }
futures = "0.3.30"
regex = "1.10.5"
schemars = "0.8.21"
schemars = { version = "0.8.21", optional = true }
serde = { version = "1.0.201", features = ["derive"] }
serde_json = "1.0.121"
serde_yaml = "0.9.34"
tokio = { version = "1.37.0", features = ["full"] }


[[bin]]
name = "commitlint"
path = "src/main.rs"
[features]
schemars = ["dep:schemars"]
default = []

[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/commitlint-v{ version }-{ target }{ archive-suffix }"
1 change: 1 addition & 0 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const DEFAULT_CONFIG_FILE: [&str; 4] = [

/// Config represents the configuration of commitlint.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Config {
/// Rules represents the rules of commitlint.
pub rules: Rules,
Expand Down
12 changes: 9 additions & 3 deletions cli/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub fn parse_commit_message(
///
/// Note that exclamation mark is not respected as the existing commitlint
/// does not have any rules for it.
/// See: https://commitlint.js.org/#/reference-rules
/// See: https://commitlint.js.org/reference/rules.html
pub fn parse_subject(subject: &str) -> (Option<String>, Option<String>, Option<String>) {
let re = regex::Regex::new(
r"^(?P<type>\w+)(?:\((?P<scope>[^\)]+)\))?(?:!)?\:\s?(?P<description>.*)$",
Expand Down Expand Up @@ -188,8 +188,14 @@ Link: Hello";
let mut f = HashMap::new();
f.insert("Link".to_string(), "Hello".to_string());
assert_eq!(subject, "feat(cli): add dummy option");
assert_eq!(body, Some("Hello, there!
I'm from Japan!".to_string()));
assert_eq!(
body,
Some(
"Hello, there!
I'm from Japan!"
.to_string()
)
);
assert!(footer.is_some());
assert_eq!(f.get("Link"), Some(&"Hello".to_string()));
}
Expand Down
5 changes: 5 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod config;
pub mod git;
pub mod message;
pub mod result;
pub mod rule;
1 change: 0 additions & 1 deletion cli/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,5 @@ impl Message {
/// validate the raw commit message.
pub async fn validate(msg: &Message, config: &Config) -> Result<LintResult, Error> {
let violations = config.rules.validate(msg);

Ok(LintResult { violations })
}
4 changes: 3 additions & 1 deletion cli/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ pub mod type_format;
pub mod type_max_length;

/// Rules represents the rules of commitlint.
/// See: https://commitlint.js.org/#/reference-rules
/// See: https://commitlint.js.org/reference/rules.html
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Rules {
#[serde(rename = "body-empty")]
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -227,6 +228,7 @@ pub trait Rule: Default {

/// Level represents the level of a rule.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Level {
#[serde(rename = "error")]
Error,
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/body_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// BodyEmpty represents the body-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct BodyEmpty {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/body_max_length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// BodyMaxLength represents the body-max-length rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct BodyMaxLength {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/description_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// DescriptionEmpty represents the subject-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DescriptionEmpty {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/description_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// DescriptionFormat represents the description-format rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DescriptionFormat {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/description_max_length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// DescriptionMaxLength represents the description-max-length rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DescriptionMaxLength {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/footers_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// FootersEmpty represents the footer-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct FootersEmpty {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// Scope represents the subject-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Scope {
/// Level represents the level of the rule.
///
Expand Down
11 changes: 3 additions & 8 deletions cli/src/rule/scope_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// ScopeEmpty represents the subject-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ScopeEmpty {
/// Level represents the level of the rule.
///
Expand Down Expand Up @@ -79,10 +80,7 @@ mod tests {
let violation = rule.validate(&message);
assert!(violation.is_some());
assert_eq!(violation.clone().unwrap().level, Level::Error);
assert_eq!(
violation.unwrap().message,
"scope is empty".to_string()
);
assert_eq!(violation.unwrap().message, "scope is empty".to_string());
}

#[test]
Expand All @@ -101,9 +99,6 @@ mod tests {
let violation = rule.validate(&message);
assert!(violation.is_some());
assert_eq!(violation.clone().unwrap().level, Level::Error);
assert_eq!(
violation.unwrap().message,
"scope is empty".to_string()
);
assert_eq!(violation.unwrap().message, "scope is empty".to_string());
}
}
1 change: 1 addition & 0 deletions cli/src/rule/scope_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// ScopeFormat represents the scope-format rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ScopeFormat {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/scope_max_length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// ScopeMaxLength represents the description-max-length rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ScopeMaxLength {
/// Level represents the level of the rule.
///
Expand Down
6 changes: 2 additions & 4 deletions cli/src/rule/subject_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// SubjectEmpty represents the subject-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SubjectEmpty {
/// Level represents the level of the rule.
///
Expand Down Expand Up @@ -85,9 +86,6 @@ Hello world"
let violation = rule.validate(&message);
assert!(violation.is_some());
assert_eq!(violation.clone().unwrap().level, Level::Error);
assert_eq!(
violation.unwrap().message,
"subject is empty".to_string()
);
assert_eq!(violation.unwrap().message, "subject is empty".to_string());
}
}
1 change: 1 addition & 0 deletions cli/src/rule/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// Type represents the subject-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Type {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/type_empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// TypeEmpty represents the type-empty rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct TypeEmpty {
/// Level represents the level of the rule.
///
Expand Down
1 change: 1 addition & 0 deletions cli/src/rule/type_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::Level;

/// TypeFormat represents the type-format rule.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct TypeFormat {
/// Level represents the level of the rule.
///
Expand Down
Loading

0 comments on commit 91bd0a7

Please sign in to comment.