Skip to content

Commit

Permalink
feat(lint): Implement auto-fix functionality (#5)
Browse files Browse the repository at this point in the history
* implement fixing changelog contents

* remove unused fields in entry and address unused import
  • Loading branch information
MalteHerrmann authored May 31, 2024
1 parent c33f10e commit b24bd9d
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 65 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@

### Features

- (lint) [#5](https://github.com/MalteHerrmann/changelog-utils/pull/5) Implement fix flag for linter CLI.
- (lint) [#4](https://github.com/MalteHerrmann/changelog-utils/pull/4) Rewrite linter implementation in Rust.
- (lint) [#1](https://github.com/MalteHerrmann/changelog-utils/pull/1) Add initial implementation for linter in Python.
- (lint) [#1](https://github.com/MalteHerrmann/changelog-utils/pull/1) Add initial implementation for linter in Python.
10 changes: 2 additions & 8 deletions src/change_type.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
use crate::{config, entry::Entry, errors::ChangeTypeError};
use crate::{config, errors::ChangeTypeError};
use regex::{Regex, RegexBuilder};

#[derive(Clone, Debug)]
pub struct ChangeType {
pub name: String,
line: String,
fixed: String,
pub fixed: String,
pub problems: Vec<String>,
entries: Vec<Entry>,
}

pub fn new_empty_change_type() -> ChangeType {
ChangeType{
name: "".to_string(),
line: "".to_string(),
fixed: "".to_string(),
problems: Vec::new(),
entries: Vec::new(),
}
}

Expand Down Expand Up @@ -65,10 +61,8 @@ pub fn parse(config: config::Config, line: &str) -> Result<ChangeType, ChangeTyp

Ok(ChangeType {
name: fixed_name,
line: line.to_string(),
fixed,
problems,
entries: Vec::new(),
})
}

Expand Down
19 changes: 16 additions & 3 deletions src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{change_type, config::Config, entry, errors::ChangelogError, release}
/// Represents the changelog contents.
#[derive(Debug)]
pub struct Changelog {
pub fixed: Vec<String>,
pub releases: HashMap<String, release::Release>,
pub problems: Vec<String>
}
Expand All @@ -13,6 +14,7 @@ pub struct Changelog {
///
/// TODO: implement fix functionality
pub fn parse_changelog(config: Config, contents: &str) -> Result<Changelog, ChangelogError> {
let mut fixed: Vec<String> = Vec::new();
let mut releases: HashMap<String, release::Release> = HashMap::new();
let mut problems: Vec<String> = Vec::new();

Expand All @@ -33,15 +35,18 @@ pub fn parse_changelog(config: Config, contents: &str) -> Result<Changelog, Chan
// TODO: improve this?
if enter_comment_regex.is_match(trimmed_line) {
is_comment = true;
fixed.push(line.to_string());
continue
}

if is_comment && exit_comment_regex.is_match(trimmed_line) {
is_comment = false;
fixed.push(line.to_string());
continue
}

if is_comment {
fixed.push(line.to_string());
continue
}

Expand Down Expand Up @@ -70,6 +75,8 @@ pub fn parse_changelog(config: Config, contents: &str) -> Result<Changelog, Chan
problems.push(rel_prob.to_string())
}

fixed.push(current_release.fixed);

continue
}

Expand All @@ -91,18 +98,22 @@ pub fn parse_changelog(config: Config, contents: &str) -> Result<Changelog, Chan
problems.push(ct_prob.to_string())
}

fixed.push(current_change_type.fixed);

continue
}

if !trimmed_line.starts_with("-") || is_legacy {
fixed.push(line.to_string());
continue
}

// TODO: remove clone?
let current_entry = match entry::parse(config.clone(), line) {
Ok(e) => e,
Err(e) => {
problems.push(e.to_string());
Err(ee) => {
problems.push(ee.to_string());
fixed.push(line.to_string());
continue
}
};
Expand All @@ -122,7 +133,9 @@ pub fn parse_changelog(config: Config, contents: &str) -> Result<Changelog, Chan
for entry_prob in &current_entry.problems {
problems.push(entry_prob.to_string());
}

fixed.push(current_entry.fixed)
}

Ok(Changelog { releases, problems })
Ok(Changelog { fixed, releases, problems })
}
11 changes: 8 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use clap::Parser;
use clap::{Args, Parser};

#[derive(Parser, Debug)]
pub enum ChangelogCLI {
#[command(about = "Lint the changelog contents")]
Lint,
Lint(LintArgs),
}

#[derive(Args, Debug)]
pub struct LintArgs {
#[arg(short, long)]
pub fix: bool
}
42 changes: 1 addition & 41 deletions src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ use regex::{Error, Regex, RegexBuilder};
/// Represents an individual entry in the changelog.
#[derive(Clone, Debug)]
pub struct Entry {
/// The original line from the parsed changelog.
line: String,
/// The fixed line adhering to all standards.
fixed: String,
/// The category of the given entry, e.g. (tests).
category: String,
/// The description of the changes.
description: String,
pub fixed: String,
/// The PR number for the given change.
pub pr_number: u16,
/// The link to the PR
link: String,
/// The list of problems with the given line.
///
/// TODO: Should this rather be a Vec<a' str>?
Expand Down Expand Up @@ -81,11 +73,7 @@ pub fn parse(config: config::Config, line: &str) -> Result<Entry, EntryError> {
);

Ok(Entry {
line: line.to_string(),
fixed, // TODO: why is it not possible to have this as &'a str too?
category: category.to_string(),
description: description.to_string(),
link: link.to_string(),
pr_number,
// TODO: implement describing problems in line
problems,
Expand Down Expand Up @@ -288,15 +276,8 @@ mod entry_tests {
let entry_res = parse(load_test_config(), example);
assert!(entry_res.is_ok());
let entry = entry_res.unwrap();
assert_eq!(entry.line, example);
assert_eq!(entry.fixed, example); // NOTE: since line is okay there are no changes to it in the fixed version
assert_eq!(entry.category, "cli");
assert_eq!(entry.pr_number, 1);
assert_eq!(
entry.link,
"https://github.com/MalteHerrmann/changelog-utils/pull/1"
);
assert_eq!(entry.description, "Add initial Python implementation.");
assert!(entry.problems.is_empty());
}

Expand All @@ -308,15 +289,8 @@ mod entry_tests {
// TODO: should this actually return an error? Not really, because parsing has worked??
assert!(entry_res.is_ok());
let entry = entry_res.unwrap();
assert_eq!(entry.line, example);
assert_eq!(entry.fixed, example.replace(r"\", ""));
assert_eq!(entry.category, "cli");
assert_eq!(entry.pr_number, 1);
assert_eq!(
entry.link,
"https://github.com/MalteHerrmann/changelog-utils/pull/1"
);
assert_eq!(entry.description, "Test.");
assert_eq!(entry.problems.len(), 1);
assert_eq!(
entry.problems[0],
Expand All @@ -331,15 +305,8 @@ mod entry_tests {
let entry_res = parse(load_test_config(), example);
assert!(entry_res.is_ok());
let entry = entry_res.unwrap();
assert_eq!(entry.line, example);
assert_eq!(entry.fixed, fixed);
assert_eq!(entry.category, "cli");
assert_eq!(entry.pr_number, 2);
assert_eq!(
entry.link,
"https://github.com/MalteHerrmann/changelog-utils/pull/1"
);
assert_eq!(entry.description, "Test");
assert_eq!(entry.problems.len(), 2);
assert_eq!(
entry.problems,
Expand Down Expand Up @@ -369,15 +336,8 @@ mod entry_tests {
let entry_res = parse(load_test_config(), example);
assert!(entry_res.is_ok());
let entry = entry_res.unwrap();
assert_eq!(entry.line, example);
assert_eq!(entry.fixed, expected);
assert_eq!(entry.category, "cli");
assert_eq!(entry.pr_number, 1);
assert_eq!(
entry.link,
"https://github.com/MalteHerrmann/changelog-utils/pull/1"
);
assert_eq!(entry.description, "Run test.");
assert_eq!(entry.problems.len(), 2);
assert_eq!(
entry.problems,
Expand Down
21 changes: 15 additions & 6 deletions src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{fs, path::Path};

/// Runs the main logic for the linter, by searching for the changelog file in the
/// current directory and then executing the linting on the found file.
pub fn run() -> Result<(), LintError> {
pub fn run(fix: bool) -> Result<(), LintError> {
let changelog_file = match fs::read_dir(Path::new("./"))?.find(|e| {
e.as_ref()
.is_ok_and(|e| e.file_name().to_ascii_lowercase() == "changelog.md")
Expand All @@ -27,15 +27,24 @@ pub fn run() -> Result<(), LintError> {
let changelog = lint(config, &changelog_file.path())?;
match changelog.problems.is_empty() {
true => {
println!("changelog has no problems");
println ! ("changelog has no problems");
Ok(())
},
false => {
println!("found problems in changelog:");
for problem in changelog.problems {
println!("{}", problem);
match fix {
false => {
println!("found problems in changelog:");
for problem in changelog.problems {
println!("{}", problem);
}
Err(LintError::ProblemsInChangelog)
},
true => {
fs::write(changelog_file.path(), changelog.fixed.join("\n"))?;
println!("automated fixes were applied to {}", changelog_file.path().to_string_lossy());
Ok(())
}
}
Err(LintError::ProblemsInChangelog)
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use clu::{cli::ChangelogCLI, errors::CLIError, lint};
use clap::Parser;

fn main() -> Result<(), CLIError>{
match ChangelogCLI::parse() {
ChangelogCLI::Lint => {
Ok(lint::run()?)
let cli = ChangelogCLI::parse();
match cli {
ChangelogCLI::Lint(args) => {
Ok(lint::run(args.fix)?)
}
}
}

0 comments on commit b24bd9d

Please sign in to comment.