Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Documentation needed for the schemars feature flag

The optional dependency is well-implemented, but it lacks documentation. Please add documentation in the README.md or cli/README.md explaining:

  • The purpose of the schemars feature flag
  • How to enable it
  • When users might want to use it
🔗 Analysis chain

LGTM! Well-structured feature flag implementation.

The optional dependency and feature flag setup looks good. Making schemars optional and not enabled by default is the right approach since schema generation is a development-time feature.

Let's verify that the feature flag is properly documented:

Also applies to: 33-35


Let me check if there's any documentation about this feature in other common documentation locations before making the final response.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the feature is documented in README or other docs
rg -i "schemars.*feature" README.md || echo "Feature documentation not found in README.md"

Length of output: 136


Script:

#!/bin/bash
# Check docs directory and other common documentation locations
fd -e md -e txt . | xargs rg -i "schemars.*feature"

# Also check if there's any documentation in the cli directory itself
fd -e md -e txt . cli/ | xargs rg -i "schemars.*feature"

# Look for any general feature documentation that might include schemars
fd -e md -e txt . | xargs rg -i "feature.*schema"

Length of output: 164

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 @@ -68,7 +68,7 @@
/// See: https://www.conventionalcommits.org/en/v1.0.0/#summary
///
/// ```
/// <type>[optional scope]: <description> <-- Subject

Check failure on line 71 in cli/src/git.rs

View workflow job for this annotation

GitHub Actions / test

expected type, found keyword `type`
///
/// [optional body] <-- Body
///
Expand Down Expand Up @@ -117,7 +117,7 @@
///
/// 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 @@
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.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect documentation.

The struct documentation incorrectly states "DescriptionEmpty represents the subject-empty rule" when it should be "description-empty rule".

Apply this fix:

- /// DescriptionEmpty represents the subject-empty rule.
+ /// DescriptionEmpty represents the description-empty rule.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// DescriptionEmpty represents the subject-empty rule.
/// DescriptionEmpty represents the description-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
Loading