Skip to content

Commit

Permalink
support glob pattern for task runner (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
DenysVuika authored Nov 20, 2024
1 parent d282642 commit 3ac6fcb
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 15 deletions.
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Options:
- `files` - List affected files
- `projects` - List affected projects
- `tasks` - List defined tasks
- `run [task]` - Run a task on affected files or projects
- `run [task|glob]` - Run a task on affected files or projects

For more information on a command, use the `help` command.

Expand Down Expand Up @@ -136,10 +136,17 @@ tasks:
- npx prettier --check {files}
```
Example:
Examples:
```bash
# view the tasks defined in the configuration file
affected view tasks

# run the task named 'lint'
affected run lint

# run tasks by a glob pattern (e.g. 'project:1', 'project:2', etc.)
affected run "project:*"
```

### File Separators
Expand All @@ -160,6 +167,41 @@ tasks:
The default separator is a space.
### Using Glob Patterns
Glob patterns can be used to run multiple tasks on different file types.
```yaml
# .affected.yml
base: develop
tasks:
- name: echo:1
description: Echoes the affected files (example)
patterns:
- '*'
commands:
- echo 'one'
- name: echo:2
description: Echoes the affected files (example)
patterns:
- '*'
commands:
- echo 'two'
```
Run the tasks:
```bash
affected run "echo:*"
```

The output is:

```bash
one
two
```

### Environment Variables

Environment variables can be set in the `.env` file in the root of the repository.
Expand Down Expand Up @@ -228,6 +270,8 @@ LOG_LEVEL=DEBUG affected run lint

## Recipes

Below are some examples of tasks that can be defined in the `.affected.yml` file.

### Run ESLint on affected files

```yaml
Expand Down
16 changes: 15 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Result;
use globset::Glob;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::fs::File;
Expand All @@ -18,6 +19,19 @@ impl Config {
.as_ref()
.and_then(|tasks| tasks.iter().find(|task| task.name == task_name))
}

pub fn get_tasks(&self, pattern: &str) -> Vec<&Task> {
let glob = Glob::new(pattern).unwrap().compile_matcher();
self.tasks
.as_ref()
.map(|tasks| {
tasks
.iter()
.filter(|task| glob.is_match(&task.name))
.collect()
})
.unwrap_or_default()
}
}

impl Default for Config {
Expand Down Expand Up @@ -45,7 +59,7 @@ impl Default for Config {
}

#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize)]
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Task {
pub name: String,
pub description: Option<String>,
Expand Down
20 changes: 17 additions & 3 deletions src/tasks.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
use crate::config::Task;
use crate::workspace::Workspace;
use anyhow::{bail, Context, Result};
use globset::{Glob, GlobSetBuilder};
use log::debug;
use std::process::Stdio;
use tokio::process::Command;

pub async fn run_task_by_name(workspace: &Workspace, task_name: &str) -> Result<()> {
debug!("Running task: {}", task_name);
pub async fn run_tasks(workspace: &Workspace, pattern: &str) -> Result<()> {
let config = workspace.config().context("No configuration found")?;
let task = config.get_task(task_name).context("Task not found")?;
let tasks = config.get_tasks(pattern);

if tasks.is_empty() {
println!("No tasks matched the pattern");
return Ok(());
}

for task in tasks {
run_task(workspace, task).await?;
}

Ok(())
}

async fn run_task(workspace: &Workspace, task: &Task) -> Result<()> {
let file_paths = workspace.affected_files()?;

// filter out files that exist on the filesystem
Expand Down
17 changes: 8 additions & 9 deletions src/workspace.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::Task;
use crate::graph::{NodeType, ProjectNode};
use crate::nx::NxProject;
use crate::projects::Project;
Expand Down Expand Up @@ -97,18 +98,16 @@ impl Workspace {
}

/// Returns a list of tasks defined in the configuration
pub fn tasks(&self) -> Vec<String> {
pub fn tasks(&self) -> Vec<&Task> {
let config = self.config.as_ref().expect("Configuration not loaded");

if let Some(tasks) = &config.tasks {
tasks.iter().map(|task| task.name.clone()).collect()
} else {
vec![]
}
config
.tasks
.as_ref()
.map_or_else(Vec::new, |tasks| tasks.iter().collect())
}

pub async fn run_task(&self, task_name: &str) -> Result<()> {
crate::tasks::run_task_by_name(self, task_name).await
pub async fn run_task(&self, pattern: &str) -> Result<()> {
crate::tasks::run_tasks(self, pattern).await
}

pub fn is_project_dir(path: &Path) -> bool {
Expand Down

0 comments on commit 3ac6fcb

Please sign in to comment.