Skip to content

Commit 7b8e3a7

Browse files
Add support for config file (#9)
## Summary Allows users to use a .github/action-format.toml ## Test Plan Added tests.
1 parent 7ca0e8d commit 7b8e3a7

11 files changed

Lines changed: 634 additions & 4 deletions

File tree

.github/action-format.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Configuration for action-format
2+
# See: https://github.com/MatthewMckee4/action-format
3+
4+
# Files to ignore (release.yml uses auto-generated changelog formatting)
5+
ignore = ["release.yml"]

Cargo.lock

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ fs-err = "3.2"
2323
insta = { version = "1.44", features = ["filters"] }
2424
owo-colors = "4.2"
2525
regex = "1.12"
26+
serde = { version = "1.0", features = ["derive"] }
2627
similar = { version = "2.7", features = ["inline"] }
2728
tempfile = "3.23"
2829
terminal_size = "0.4"
2930
thiserror = "2.0"
31+
toml = "0.8"
3032
walkdir = "2.5"
3133

3234
[workspace.lints.clippy]

crates/action-format-core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ authors.workspace = true
99
license.workspace = true
1010

1111
[dependencies]
12+
serde = { workspace = true }
1213
thiserror = { workspace = true }
14+
toml = { workspace = true }
1315

1416
[lints]
1517
workspace = true
Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
use std::path::Path;
2+
3+
use serde::Deserialize;
4+
15
/// Configuration for the formatter.
2-
#[derive(Debug, Clone)]
6+
#[derive(Debug, Clone, Deserialize)]
7+
#[serde(default)]
38
pub struct FormatterConfig {
49
/// Number of spaces for indentation (default: 2)
510
pub indent_size: usize,
611
/// Whether to add blank lines between steps (default: true)
712
pub separate_steps: bool,
813
/// Whether to add blank lines between jobs (default: true)
914
pub separate_jobs: bool,
15+
/// Files to ignore (can be full paths like `.github/workflows/ci.yml` or just filenames like `ci.yml`)
16+
pub ignore: Vec<String>,
1017
}
1118

1219
impl Default for FormatterConfig {
@@ -15,6 +22,56 @@ impl Default for FormatterConfig {
1522
indent_size: 2,
1623
separate_steps: true,
1724
separate_jobs: true,
25+
ignore: Vec::new(),
1826
}
1927
}
2028
}
29+
30+
impl FormatterConfig {
31+
/// Load configuration from a TOML file, falling back to defaults if file doesn't exist.
32+
pub fn from_file(path: &Path) -> Result<Self, ConfigError> {
33+
if !path.exists() {
34+
return Ok(Self::default());
35+
}
36+
37+
let content = std::fs::read_to_string(path).map_err(|e| ConfigError::Read {
38+
path: path.to_path_buf(),
39+
source: e,
40+
})?;
41+
42+
toml::from_str(&content).map_err(|e| ConfigError::Parse {
43+
path: path.to_path_buf(),
44+
source: e,
45+
})
46+
}
47+
48+
/// Check if a file should be ignored based on the ignore patterns.
49+
pub fn should_ignore(&self, path: &Path) -> bool {
50+
let path_str = path.to_string_lossy();
51+
let file_name = path.file_name().and_then(|n| n.to_str());
52+
53+
self.ignore.iter().any(|pattern| {
54+
// Match full path
55+
path_str == *pattern
56+
|| path_str.ends_with(pattern)
57+
// Match just the filename
58+
|| file_name.is_some_and(|name| name == pattern)
59+
})
60+
}
61+
}
62+
63+
#[derive(Debug, thiserror::Error)]
64+
pub enum ConfigError {
65+
#[error("failed to read config file '{path}'")]
66+
Read {
67+
path: std::path::PathBuf,
68+
#[source]
69+
source: std::io::Error,
70+
},
71+
#[error("failed to parse config file '{path}'")]
72+
Parse {
73+
path: std::path::PathBuf,
74+
#[source]
75+
source: toml::de::Error,
76+
},
77+
}

crates/action-format-core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ mod config;
22
mod formatter;
33
mod parser;
44

5-
pub use config::FormatterConfig;
5+
pub use config::{ConfigError, FormatterConfig};
66
pub use formatter::{format_file, format_string};
77
pub use parser::FormatError;

crates/action-format/src/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod printer;
1414
use printer::Printer;
1515

1616
const WORKFLOWS_DIR: &str = ".github/workflows";
17+
const CONFIG_FILE: &str = ".github/action-format.toml";
1718

1819
#[derive(Copy, Clone)]
1920
pub enum ExitStatus {
@@ -71,15 +72,18 @@ fn run(cli: &Cli, printer: Printer) -> Result<ExitStatus> {
7172
anyhow::bail!("No {WORKFLOWS_DIR} directory found");
7273
}
7374

74-
let config = FormatterConfig::default();
75+
let config_path = Path::new(CONFIG_FILE);
76+
let config = FormatterConfig::from_file(config_path)?;
77+
7578
let mut any_changed = false;
7679
let mut any_error = false;
7780

7881
let walker = walkdir::WalkDir::new(workflows_path)
7982
.sort_by_file_name()
8083
.into_iter()
8184
.filter_map(Result::ok)
82-
.filter(|e| is_workflow_file(e.path()));
85+
.filter(|e| is_workflow_file(e.path()))
86+
.filter(|e| !config.should_ignore(e.path()));
8387

8488
for entry in walker {
8589
match process_file(entry.path(), &config, cli, printer) {

crates/action-format/tests/it/common/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ impl TestContext {
7676
self
7777
}
7878

79+
/// Create a config file at .github/action-format.toml with the given content.
80+
pub fn config(&self, content: &str) -> &Self {
81+
self.root
82+
.child(".github/action-format.toml")
83+
.write_str(content.strip_prefix('\n').unwrap_or(content))
84+
.expect("Failed to write config file");
85+
self
86+
}
87+
7988
/// Read a file from .github/workflows and return its contents.
8089
pub fn read_workflow(&self, name: &str) -> String {
8190
std::fs::read_to_string(self.root.join(format!(".github/workflows/{name}")))

0 commit comments

Comments
 (0)