feat: Add Task Filtering and Tagging Capabilities#242
feat: Add Task Filtering and Tagging Capabilities#242thalesraymond wants to merge 1 commit intomainfrom
Conversation
- Added `tags?: string[]` property to `TaskStep`. - Introduced `TaskFilterConfig` interface to configure filters and dependencies. - Created `src/utils/TaskFilter.ts` containing the `filterTasks` logic. - Updated `TaskRunnerExecutionConfig` with the new optional `filter` property. - Integrated filtering in `TaskRunner.execute` to process steps prior to graph execution. - Added comprehensive unit tests and E2E integration tests to verify functionality. - Marked all spec tasks as complete and archived OpenSpec change `add-task-filtering`. Co-authored-by: thalesraymond <32554150+thalesraymond@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request implements task filtering within the TaskRunner, allowing users to selectively execute tasks based on names or tags. Key changes include the addition of a TaskFilterConfig interface, the inclusion of optional tags in TaskStep, and the implementation of a filterTasks utility that supports recursive dependency resolution. Review feedback suggests removing redundant JSDoc blocks in TaskRunnerExecutionConfig.ts and improving type safety in TaskFilter.ts by replacing non-null assertions with optional chaining and explicit null checks.
| /** | ||
| * Configuration options for TaskRunner execution. | ||
| */ | ||
| import { TaskFilterConfig } from "./contracts/TaskFilterConfig.js"; |
| const filteredSteps = steps.filter((step) => { | ||
| // 1. Check exclusions first (highest priority) | ||
| if ( | ||
| config.excludeNames?.includes(step.name) || | ||
| (step.tags && config.excludeTags?.some((tag) => step.tags!.includes(tag))) | ||
| ) { | ||
| return false; | ||
| } | ||
|
|
||
| // 2. Check inclusions (if both are provided, satisfying either is enough or requires both? Usually OR semantics for inclusions) | ||
| // Actually, usually if include is present, it MUST match one of the inclusions. | ||
| // Let's implement OR logic: if included by name OR included by tag. | ||
| const hasIncludeNames = | ||
| config.includeNames && config.includeNames.length > 0; | ||
| const hasIncludeTags = config.includeTags && config.includeTags.length > 0; | ||
|
|
||
| if (!hasIncludeNames && !hasIncludeTags) { | ||
| return true; // No inclusion filters, so keep it if it passed exclusion | ||
| } | ||
|
|
||
| const includedByName = hasIncludeNames && config.includeNames!.includes(step.name); | ||
| const includedByTag = | ||
| hasIncludeTags && | ||
| step.tags && | ||
| config.includeTags!.some((tag) => step.tags!.includes(tag)); | ||
|
|
||
| return includedByName || includedByTag; | ||
| }); |
There was a problem hiding this comment.
The filtering logic uses several non-null assertion operators (!), which violates the project's general rules. Additionally, the logic can be simplified and made more robust by using optional chaining and nullish coalescing to handle potentially undefined properties like tags or includeNames.
const filteredSteps = steps.filter((step) => {
// 1. Check exclusions first (highest priority)
const isExcludedByName = config.excludeNames?.includes(step.name) ?? false;
const isExcludedByTag = step.tags?.some((tag) => config.excludeTags?.includes(tag)) ?? false;
if (isExcludedByName || isExcludedByTag) {
return false;
}
// 2. Check inclusions
const hasIncludeNames = (config.includeNames?.length ?? 0) > 0;
const hasIncludeTags = (config.includeTags?.length ?? 0) > 0;
if (!hasIncludeNames && !hasIncludeTags) {
return true;
}
const includedByName = config.includeNames?.includes(step.name) ?? false;
const includedByTag = step.tags?.some((tag) => config.includeTags?.includes(tag)) ?? false;
return includedByName || includedByTag;
});References
- In TypeScript, avoid using the non-null assertion operator (!). Instead, use explicit checks or safe fallbacks like the nullish coalescing operator (??) to handle potentially null or undefined values.
| const queue = [...filteredSteps]; | ||
|
|
||
| while (queue.length > 0) { | ||
| const current = queue.shift()!; |
There was a problem hiding this comment.
Avoid using the non-null assertion operator (!). Although the queue length is checked, it is better practice to handle the potential undefined return from shift() explicitly to adhere to the project's safety rules.
const current = queue.shift();
if (!current) continue;References
- In TypeScript, avoid using the non-null assertion operator (!). Instead, use explicit checks or safe fallbacks like the nullish coalescing operator (??) to handle potentially null or undefined values.



Implement
add-task-filteringspecification from OpenSpec, allowing users to selectively execute tasks based on tags or names with dependency resolution capabilities.PR created automatically by Jules for task 15239283241663882048 started by @thalesraymond