Skip to content

read task info from list format instead of CSV#547

Merged
creativeprojects merged 7 commits intomasterfrom
task-info-from-list
Aug 5, 2025
Merged

read task info from list format instead of CSV#547
creativeprojects merged 7 commits intomasterfrom
task-info-from-list

Conversation

@creativeprojects
Copy link
Copy Markdown
Owner

Refactor Windows task scheduler to use list format instead of CSV

This PR refactors the Windows task scheduler implementation to read task information from the schtasks list format instead of CSV format.

Key Changes:

  • New parser: Added getTaskInfoFromList() function to parse key-value pairs from list format output
  • Command change: Modified schtasks command to use /fo list instead of /fo csv
  • Data structure: Changed from [][]string (CSV rows) to []map[string]string (key-value records)
  • Improved parsing: Better handling of different separator formats (: and : )
  • Enhanced testing: Added comprehensive tests for the new list format parser

Benefits:

  • More robust parsing of task information
  • Better handling of complex field values that may contain quotes
  • Cleaner data structure for accessing task properties by name
  • Improved error handling for malformed data

The change maintains backward compatibility while providing a more reliable way to extract Windows scheduled task information.

Fixes #545

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 4, 2025

Walkthrough

The changes introduce a new Windows YAML configuration example and refactor the Windows scheduled task parsing logic from CSV-based to LIST-based output. New parsing and test logic for LIST-formatted output are added, and related functions and tests are updated. Logging and error handling are also adjusted accordingly.

Changes

Cohort / File(s) Change Summary
Windows YAML Example
examples/other windows.yaml
Adds a new YAML configuration file for resticprofile with backup profiles, scheduling, and logging settings.
LIST Format Parsing Implementation
schtasks/list.go, schtasks/list_test.go
Introduces new logic and tests for parsing Windows scheduled task output in LIST format, including error handling and field extraction.
Scheduled Task Parsing Refactor
schtasks/schtasks.go, schtasks/schtasks_test.go
Refactors task detail parsing from CSV to LIST format, updates function signatures, renames helpers, and adjusts related tests.
Task Scheduler Logging and Helper Removal
schtasks/taskscheduler.go
Adds debug logging, changes error formatting, and removes the obsolete CSV field extraction helper.
Profile Test Adjustment
config/profile_test.go
Updates test assertions to use escaped shell arguments for backup source paths.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TaskScheduler
    participant schtasks.exe
    participant Parser

    User->>TaskScheduler: Request registered tasks
    TaskScheduler->>schtasks.exe: Run schtasks /query /fo list /v /tn "task"
    schtasks.exe-->>TaskScheduler: Returns LIST-formatted output
    TaskScheduler->>Parser: Parse output with getTaskInfoFromList
    Parser-->>TaskScheduler: Returns parsed task info (map)
    TaskScheduler-->>User: Returns registered task details
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Assessment against linked issues

Objective Addressed Explanation
Correctly parse scheduled tasks on Windows when arguments contain double quotes (#545)
Refactor parsing logic away from CSV-based approach to avoid parse errors (#545)
Update tests to verify correct parsing of LIST-formatted output (#545)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes were identified.

Suggested labels

enhancement

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf27132 and 50abe54.

📒 Files selected for processing (1)
  • schtasks/list_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • schtasks/list_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (1.24, ubuntu-latest)
  • GitHub Check: Build and test (1.24, windows-latest)
  • GitHub Check: Build and test (1.24, macos-latest)
  • GitHub Check: Analyze (go)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch task-info-from-list

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
examples/other windows.yaml (1)

1-1: Fix line ending format.

The static analysis tool flagged an incorrect line ending character. Please ensure the file uses LF (\n) line endings as expected.

-# yaml-language-server: $schema=https://creativeprojects.github.io/resticprofile/jsonschema/config.json
+# yaml-language-server: $schema=https://creativeprojects.github.io/resticprofile/jsonschema/config.json
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9039fa and c92c260.

📒 Files selected for processing (6)
  • examples/other windows.yaml (1 hunks)
  • schtasks/list.go (1 hunks)
  • schtasks/list_test.go (1 hunks)
  • schtasks/schtasks.go (3 hunks)
  • schtasks/schtasks_test.go (2 hunks)
  • schtasks/taskscheduler.go (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: schtasks/schtasks.go:29-30
Timestamp: 2025-02-14T22:53:42.689Z
Learning: In the `schtasks` package, `tasksPath` is defined as a constant with value `\resticprofile backup\` in `taskscheduler.go`. It's used as a prefix for managing task paths in the Windows Task Scheduler.
Learnt from: zumm
PR: creativeprojects/resticprofile#541
File: schtasks/taskscheduler.go:60-67
Timestamp: 2025-07-29T16:14:02.636Z
Learning: In the schtasks package, double quotes cannot be used for command wrapping because `getTaskInfo` can't process them and unschedule commands fail when double quotes are used.
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: examples/windows.yaml:41-41
Timestamp: 2025-02-14T22:53:45.818Z
Learning: Changes to example configurations in the `examples/` directory do not require changelog entries as they are meant for testing and demonstration purposes only.
📚 Learning: in the `schtasks` package, `taskspath` is defined as a constant with value `\resticprofile backup\` ...
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: schtasks/schtasks.go:29-30
Timestamp: 2025-02-14T22:53:42.689Z
Learning: In the `schtasks` package, `tasksPath` is defined as a constant with value `\resticprofile backup\` in `taskscheduler.go`. It's used as a prefix for managing task paths in the Windows Task Scheduler.

Applied to files:

  • schtasks/taskscheduler.go
  • schtasks/list_test.go
  • schtasks/schtasks.go
  • schtasks/list.go
  • examples/other windows.yaml
📚 Learning: the shell.splitarguments function in the resticprofile project returns only []string and does not re...
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#425
File: schedule/handler_windows.go:97-118
Timestamp: 2025-02-04T14:38:07.701Z
Learning: The shell.SplitArguments function in the resticprofile project returns only []string and does not return any error.

Applied to files:

  • schtasks/list_test.go
  • schtasks/list.go
📚 Learning: in the `schtasks` package, `taskspath` is defined as a constant and is used for filtering registered...
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: schtasks/schtasks.go:29-30
Timestamp: 2025-02-14T22:53:42.689Z
Learning: In the `schtasks` package, `tasksPath` is defined as a constant and is used for filtering registered tasks by their path prefix.

Applied to files:

  • schtasks/schtasks.go
📚 Learning: in the schtasks package, double quotes cannot be used for command wrapping because `gettaskinfo` can...
Learnt from: zumm
PR: creativeprojects/resticprofile#541
File: schtasks/taskscheduler.go:60-67
Timestamp: 2025-07-29T16:14:02.636Z
Learning: In the schtasks package, double quotes cannot be used for command wrapping because `getTaskInfo` can't process them and unschedule commands fail when double quotes are used.

Applied to files:

  • schtasks/list.go
📚 Learning: in the schtasks package, `config.command` is guaranteed to be just a path to executable, making sing...
Learnt from: zumm
PR: creativeprojects/resticprofile#541
File: schtasks/taskscheduler.go:60-67
Timestamp: 2025-07-29T16:14:02.636Z
Learning: In the schtasks package, `config.Command` is guaranteed to be just a path to executable, making single quotes sufficient for wrapping in command construction.

Applied to files:

  • schtasks/list.go
📚 Learning: changes to example configurations in the `examples/` directory do not require changelog entries as t...
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: examples/windows.yaml:41-41
Timestamp: 2025-02-14T22:53:45.818Z
Learning: Changes to example configurations in the `examples/` directory do not require changelog entries as they are meant for testing and demonstration purposes only.

Applied to files:

  • examples/other windows.yaml
🪛 YAMLlint (1.37.1)
examples/other windows.yaml

[error] 1-1: wrong new line character: expected \n

(new-lines)

🔇 Additional comments (14)
examples/other windows.yaml (1)

3-34: LGTM! Well-structured Windows configuration example.

The configuration demonstrates proper usage of resticprofile features including global settings, profile inheritance, backup exclusions, and Windows task scheduling. This example complements the improved Windows task parsing capabilities introduced in this PR.

schtasks/taskscheduler.go (2)

134-134: LGTM! Helpful debug logging addition.

Adding debug logging before loading each task will improve troubleshooting capabilities when diagnosing task parsing issues.


137-137: LGTM! Appropriate error formatting change.

Changing from %w to %s is correct for logging context where error wrapping isn't needed.

schtasks/schtasks_test.go (2)

21-21: LGTM! Test updated to match refactored function name.

The test correctly calls the renamed getTaskInfoFromCSV function, maintaining coverage of CSV parsing functionality.


27-47: LGTM! Test properly updated for new function signature.

The test function rename and call to getTaskInfo correctly reflect the refactored API while maintaining proper error testing coverage.

schtasks/list_test.go (1)

74-146: LGTM! Comprehensive test coverage for list parsing.

The test provides excellent coverage of the new list format parsing functionality with realistic test data that includes quoted arguments in command lines (addressing the original issue #545). The expected output verification ensures correctness of the key-value pair parsing logic.

schtasks/list.go (2)

18-63: LGTM! Robust implementation of list format parsing.

The parser effectively addresses the original issue by handling key-value pairs instead of CSV format, which eliminates problems with quoted arguments. Good error handling for invalid formats and duplicate keys ensures reliable parsing.

Key strengths:

  • Handles both separator formats (: and : ) found in Windows schtasks output
  • Proper folder context tracking for task hierarchy
  • Efficient line-by-line processing with bufio.Scanner
  • Clear error messages for debugging

65-72: LGTM! Clean helper function for field access.

The getFirstField function provides a clean API for accessing parsed task data, replacing the previous version that worked with CSV data structures.

schtasks/schtasks.go (6)

21-21: Function rename improves clarity.

The renaming from getCSV to getTaskInfoFromCSV better reflects the specific purpose of parsing task information from CSV format, improving code readability.


36-36: Return type change enhances data access.

Changing the return type from [][]string to []map[string]string provides better structured access to task properties by name rather than requiring positional indexing, which aligns well with the switch to LIST format parsing.


49-52: Function rename maintains CSV parsing capability.

The renamed getTaskInfoFromCSV function preserves the existing CSV parsing logic, which is still needed for the getRegisteredTasks function. The implementation remains unchanged, ensuring no regression in CSV parsing functionality.


127-128: Comment accurately reflects the change.

The updated comment correctly indicates that the function returns raw output rather than specifically CSV format, which aligns with the switch to LIST format.


134-134: Command format change addresses the core issue.

The switch from /fo csv to /fo list directly addresses the parsing issue described in PR #545. The LIST format should handle quoted arguments more reliably than CSV format, which struggles with unescaped quotes within fields.

This change is critical for fixing the bug where tasks with quoted command arguments (such as configuration file paths with spaces) couldn't be parsed correctly.


42-42: Verified getTaskInfoFromList implementation

The getTaskInfoFromList function in schtasks/list.go correctly parses the LIST output and maintains robust error handling:

  • Splits each line first on ": " then on ": " to accommodate spacing variations, trimming both key and value.
  • Tracks the current folder via the Folder key and appends it to each record.
  • Returns errors for invalid line formats, duplicate keys and any scanner errors.

No further changes are required.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
config/profile_test.go (1)

828-828: Consider removing debug logging.

The t.Log(profile) statement appears to be for debugging purposes. Consider removing it unless it provides valuable test output for ongoing debugging.

-			t.Log(profile)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c92c260 and dbc0e15.

📒 Files selected for processing (1)
  • config/profile_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: schtasks/schtasks.go:29-30
Timestamp: 2025-02-14T22:53:42.689Z
Learning: In the `schtasks` package, `tasksPath` is defined as a constant with value `\resticprofile backup\` in `taskscheduler.go`. It's used as a prefix for managing task paths in the Windows Task Scheduler.
Learnt from: zumm
PR: creativeprojects/resticprofile#541
File: schtasks/taskscheduler.go:60-67
Timestamp: 2025-07-29T16:14:02.636Z
Learning: In the schtasks package, double quotes cannot be used for command wrapping because `getTaskInfo` can't process them and unschedule commands fail when double quotes are used.
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#459
File: examples/windows.yaml:41-41
Timestamp: 2025-02-14T22:53:45.818Z
Learning: Changes to example configurations in the `examples/` directory do not require changelog entries as they are meant for testing and demonstration purposes only.
📚 Learning: the shell.splitarguments function in the resticprofile project returns only []string and does not re...
Learnt from: creativeprojects
PR: creativeprojects/resticprofile#425
File: schedule/handler_windows.go:97-118
Timestamp: 2025-02-04T14:38:07.701Z
Learning: The shell.SplitArguments function in the resticprofile project returns only []string and does not return any error.

Applied to files:

  • config/profile_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Analyze (go)
  • GitHub Check: Build and test (1.24, ubuntu-latest)
  • GitHub Check: Build and test (1.24, windows-latest)
  • GitHub Check: Build and test (1.24, macos-latest)
🔇 Additional comments (2)
config/profile_test.go (2)

711-714: LGTM! Proper shell argument escaping test setup.

The introduction of expectedBackupSource with shell.NewArg(value, shell.ArgConfigEscape).String() correctly tests that backup source paths are properly escaped for shell usage, which aligns with the Windows task scheduling improvements in this PR.


829-829: LGTM! Updated assertions for escaped backup sources.

The test assertions correctly expect the escaped format (expectedBackupSource) rather than the raw format, ensuring that the shell argument escaping functionality works as intended for both implicit and explicit path copying scenarios.

Also applies to: 837-837

Comment thread schtasks/list_test.go Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Aug 5, 2025

Codecov Report

❌ Patch coverage is 90.56604% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.52%. Comparing base (f9039fa) to head (50abe54).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
schtasks/list.go 91.30% 3 Missing and 1 partial ⚠️
schtasks/taskscheduler.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #547      +/-   ##
==========================================
+ Coverage   79.45%   79.52%   +0.07%     
==========================================
  Files         136      137       +1     
  Lines       13386    13425      +39     
==========================================
+ Hits        10635    10675      +40     
  Misses       2331     2331              
+ Partials      420      419       -1     
Flag Coverage Δ
unittests 79.52% <90.57%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Aug 5, 2025

@creativeprojects
Copy link
Copy Markdown
Owner Author

PR is ready to merge,
@zumm does it work for you?

@zumm
Copy link
Copy Markdown
Contributor

zumm commented Aug 5, 2025

I have tested it with spaces in path to config file and it seems like unschedule/status commands work fine.

@creativeprojects creativeprojects added this to the v0.32.0 milestone Aug 5, 2025
@creativeprojects creativeprojects merged commit f748032 into master Aug 5, 2025
11 checks passed
@creativeprojects creativeprojects deleted the task-info-from-list branch August 5, 2025 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: can't read registered tasks on windows

2 participants