Skip to content

Conversation

@NamelessOIer
Copy link
Collaborator

@NamelessOIer NamelessOIer commented Dec 9, 2025

Summary by CodeRabbit

  • New Features

    • Added task dependency support with a new --dependency (-d) option for submission/run.
    • Supports AFTER/AFTEROK/AFTERNOTOK/AFTERANY, per-job delays, and OR semantics.
    • Dependency info included in job payloads and shown in job details.
  • Bug Fixes

    • Improved validation for dependency specs (duplicate-task checks) and clearer error messages.
    • Added new error codes for missing-dependency and DB-insert failures.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

📝 Walkthrough

Walkthrough

Adds a task-dependency subsystem: protobuf types and error codes, new CLI flags in calloc/cbatch/crun, parsing/validation utilities to populate per-task Dependencies, integration to apply dependencies before submission, and dependency-status formatting in ccontrol output.

Changes

Cohort / File(s) Summary
Proto definitions
protos/PublicDefs.proto
Adds DependencyType enum and messages DependencyCondition, Dependencies, DependencyStatus; adds dependencies to TaskToCtld and optional dependency_status to TaskInfo; adds ERR_MISSING_DEPENDENCY and ERR_DB_INSERT_FAILED ErrCode values.
Dependency parsing & validation
internal/util/string.go
Adds SetTaskDependencies(task *protos.TaskToCtld, depStr string) error; parses dependency specs (after/afterok/afternotok/afterany), supports per-job delays and compound durations, enforces separators and duplicate task-id checks, sets Dependencies.IsOr.
Error messages
internal/util/err.go
Adds ERR_MISSING_DEPENDENCY and ERR_DB_INSERT_FAILED messages; adjusts existing ERR_BEYOND_TASK_ID text.
CLI flags
internal/calloc/cmd.go, internal/cbatch/cmd.go, internal/crun/cmd.go
Introduces package-level FlagDependency string and registers --dependency / -d flag ("Conditions for job to execute") in calloc, cbatch, and crun.
Command handling
internal/calloc/calloc.go, internal/cbatch/cbatch.go, internal/crun/crun.go
Calls util.SetTaskDependencies(...) when a dependency flag or script arg is present; errors are surfaced or cause process exit per command; cbatch applies dependencies both during script-arg parsing and after parameter aggregation.
Output formatting
internal/ccontrol/output.go
Adds formatDependencyType, formatDependencyCondition, formatDependencyStatus; prints dependency status in job details when present; adjusts host-name empty-string handling.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as CLI user
    participant Cmd as Command (calloc/cbatch/crun)
    participant Parser as util.SetTaskDependencies
    participant CTLD as ctld (submission)
    participant Output as ccontrol/output

    Note right of Cmd: parse flags / script args
    User->>Cmd: invoke with --dependency / script deps
    Cmd->>Parser: SetTaskDependencies(task, depStr)
    alt parse success
        Parser-->>Cmd: task.Dependencies populated
        Cmd->>CTLD: submit TaskToCtld (includes Dependencies)
        CTLD-->>Cmd: returns TaskInfo (may include DependencyStatus)
        Cmd->>Output: printJobDetails(TaskInfo)
        Output-->>Cmd: formatted dependency status (if present)
        Cmd-->>User: displays job details
    else parse error
        Parser-->>Cmd: returns error
        Cmd-->>User: exit with error message
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • L-Xiafeng
  • RileyWen
  • Nativu5

Poem

🐰
I nibbled specs and parsed each line,
Tied jobs with waits in orderly twine.
Flags set, protos snug and neat,
Dependencies hop until they meet.
Hooray — the scheduler's rhythm is sweet.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'feat: dependency' is vague and generic. While it indicates a feature addition related to dependencies, it lacks specificity about what dependency functionality is being added or which components are affected. Enhance the title to be more specific about the dependency feature, such as 'feat: add job dependency support with --dependency flag' or 'feat: implement task dependency conditions and status tracking'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev/dependency_re

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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: 9

🧹 Nitpick comments (4)
internal/util/string.go (2)

1313-1389: Consider validating job IDs are non-zero.

Line 1366 parses the job ID but doesn't validate that it's non-zero. Zero is typically an invalid job ID in schedulers. Consider adding validation.

Apply this diff:

 		for _, jobMatch := range jobMatches {
 			jobId, _ := strconv.ParseUint(jobMatch[1], 10, 32)
+			if jobId == 0 {
+				return fmt.Errorf("invalid job ID '0' in dependency: %s", subDepStr)
+			}
 			var delaySeconds uint64 = 0

1370-1373: Document the auto-conversion behavior for numeric delays.

The code automatically treats numeric-only delay values as minutes by appending 'm'. This is a reasonable default, but it might be unexpected for users. Consider documenting this behavior in a comment or ensuring it's mentioned in user-facing documentation.

protos/PublicDefs.proto (2)

135-162: Dependency schema additions look coherent; consider adding brief docs for API users

The new DependencyType, DependencyCondition, Dependencies, and DependencyStatus definitions are structurally consistent and leave room for future extension (e.g., additional dependency types). To make this public surface easier to consume, consider adding short comments describing:

  • The intended string/CLI representation of each DependencyType (and how it maps to what internal/ccontrol/output.go prints).
  • The precise meaning of is_or and how pending plus ready_time / infinite_future / infinite_past should be interpreted by clients.

This will help keep server behavior, CLI parsing, and display formatting aligned over time.


728-729: Ensure new dependency-related ErrCode values are wired through all error-handling paths

Adding ERR_MISSING_DEPENDENCY and ERR_DB_INSERT_FAILED extends the public error enum cleanly, but callers that switch on ErrCode (CLI, frontend, logs, translations) may need updates to:

  • Provide user-friendly messages for these two new codes.
  • Avoid falling back to overly generic handling paths.

Please verify that error-to-string mappings and any user-visible messaging have been updated accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f32540e and e4695a0.

📒 Files selected for processing (10)
  • internal/calloc/calloc.go (1 hunks)
  • internal/calloc/cmd.go (2 hunks)
  • internal/cbatch/cbatch.go (2 hunks)
  • internal/cbatch/cmd.go (2 hunks)
  • internal/ccontrol/output.go (2 hunks)
  • internal/crun/cmd.go (2 hunks)
  • internal/crun/crun.go (1 hunks)
  • internal/util/err.go (2 hunks)
  • internal/util/string.go (2 hunks)
  • protos/PublicDefs.proto (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
internal/calloc/cmd.go (2)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/crun/cmd.go (1)
  • FlagDependency (43-43)
internal/crun/crun.go (4)
internal/calloc/cmd.go (1)
  • FlagDependency (49-49)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/crun/cmd.go (1)
  • FlagDependency (43-43)
internal/util/string.go (1)
  • SetTaskDependencies (1313-1389)
internal/cbatch/cbatch.go (2)
internal/util/string.go (1)
  • SetTaskDependencies (1313-1389)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/calloc/calloc.go (4)
internal/calloc/cmd.go (1)
  • FlagDependency (49-49)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/crun/cmd.go (1)
  • FlagDependency (43-43)
internal/util/string.go (1)
  • SetTaskDependencies (1313-1389)
internal/crun/cmd.go (2)
internal/calloc/cmd.go (1)
  • FlagDependency (49-49)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/ccontrol/output.go (1)
internal/util/string.go (1)
  • SecondTimeFormat (438-452)
🪛 GitHub Actions: Go Code Quality Check
internal/util/err.go

[error] 1-1: gofmt formatting issue detected. Run 'gofmt -w .' to fix formatting.

internal/cbatch/cmd.go

[error] 1-1: gofmt formatting issue detected. Run 'gofmt -w .' to fix formatting.

internal/calloc/cmd.go

[error] 1-1: gofmt formatting issue detected. Run 'gofmt -w .' to fix formatting.

internal/cbatch/cbatch.go

[error] 1-1: gofmt formatting issue detected. Run 'gofmt -w .' to fix formatting.

internal/ccontrol/output.go

[error] 1-1: gofmt formatting issue detected. Run 'gofmt -w .' to fix formatting.

🔇 Additional comments (8)
internal/calloc/cmd.go (1)

107-107: LGTM!

The flag registration follows the established pattern and the short flag -d doesn't conflict with other flags in this command.

internal/util/err.go (1)

176-176: LGTM!

The updated error message is more specific and clear compared to the generic "System error occurred" message.

internal/crun/cmd.go (2)

43-43: LGTM!

The variable declaration follows the established pattern in this file.


121-121: LGTM!

The flag registration is correct and the short flag -d doesn't conflict with existing flags.

internal/cbatch/cmd.go (1)

159-159: LGTM!

The flag registration follows the established pattern and is consistent with other commands.

internal/cbatch/cbatch.go (1)

341-346: LGTM!

The error handling is consistent with the rest of the function, properly wrapping and returning errors instead of using log.Fatal.

internal/util/string.go (1)

605-613: LGTM!

The duplicate task ID check is correctly implemented and provides a clear error message.

internal/ccontrol/output.go (1)

565-571: Dependency line integration in printJobDetails looks good

The new block cleanly gates dependency output on a non-nil DependencyStatus and non-empty formatted string, so it won’t spam empty Dependency= lines for jobs without dependencies. This is a straightforward, safe addition.

Comment on lines +466 to +471
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
log.Fatal(err)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use consistent error handling pattern.

This code uses log.Fatal(err) which exits immediately. Other validation errors in this function return wrapped errors (e.g., lines 405, 412, 476). Use the same pattern for consistency.

Apply this diff:

 	if FlagDependency != "" {
 		err := util.SetTaskDependencies(task, FlagDependency)
 		if err != nil {
-			log.Fatal(err)
+			return util.WrapCraneErr(util.ErrorCmdArg, "Invalid argument: %s", err)
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
log.Fatal(err)
}
}
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
return util.WrapCraneErr(util.ErrorCmdArg, "Invalid argument: %s", err)
}
}
🤖 Prompt for AI Agents
In internal/calloc/calloc.go around lines 466 to 471, the code currently calls
log.Fatal(err) when util.SetTaskDependencies fails; change this to return a
wrapped error consistent with surrounding validation (e.g., return
fmt.Errorf("set task dependencies: %w", err)). Also add the fmt import if
missing and ensure the function signature returns an error so this return
compiles and matches the existing error-handling pattern used elsewhere in the
function.


FlagConfigFilePath string
FlagJson bool
FlagDependency string
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Address the gofmt formatting issue.

The pipeline detected a formatting issue in this file. Run gofmt -w internal/cbatch/cmd.go to fix it.

🤖 Prompt for AI Agents
In internal/cbatch/cmd.go around line 64, the file has a gofmt formatting issue
(improper spacing/formatting around the FlagDependency declaration); run the
formatter to fix it by executing `gofmt -w internal/cbatch/cmd.go` (or `gofmt -w
.` in repo root) and commit the updated file so the code matches gofmt
formatting rules.

Comment on lines 689 to 776
func formatDependencyType(depType protos.DependencyType) string {
switch depType {
case protos.DependencyType_AFTER:
return "AFTER"
case protos.DependencyType_AFTER_ANY:
return "AFTERANY"
case protos.DependencyType_AFTER_OK:
return "AFTEROK"
case protos.DependencyType_AFTER_NOT_OK:
return "AFTERNOTOK"
default:
return "UNKNOWN"
}
}

func formatDependencyCondition(cond *protos.DependencyCondition) string {
if cond == nil {
return ""
}
depTypeStr := formatDependencyType(cond.Type)
if cond.DelaySeconds > 0 {
delayStr := util.SecondTimeFormat(int64(cond.DelaySeconds))
return fmt.Sprintf("%s:%d+%s", depTypeStr, cond.JobId, delayStr)
}
return fmt.Sprintf("%s:%d", depTypeStr, cond.JobId)
}

func formatDependencyStatus(depStatus *protos.DependencyStatus) string {
var buf strings.Builder

sep := ","
if depStatus.IsOr {
sep = "?"
}

if len(depStatus.Pending) > 0 {
var pendingStrs []string
for _, cond := range depStatus.Pending {
pendingStrs = append(pendingStrs, formatDependencyCondition(cond))
}
buf.WriteString(fmt.Sprintf("PendingDependencies=%s ", strings.Join(pendingStrs, sep)))
}

switch depStatus.GetReadyTimeType().(type) {
case *protos.DependencyStatus_ReadyTime:
readyTime := depStatus.GetReadyTime().AsTime()
if(depStatus.IsOr || len(depStatus.Pending) == 0) {
buf.WriteString(fmt.Sprintf("Status=ReadyAfter %s", readyTime.In(time.Local).Format("2006-01-02 15:04:05")))
} else {
buf.WriteString("Status=WaitForAll")
}
case *protos.DependencyStatus_InfiniteFuture:
if depStatus.GetInfiniteFuture() {
if depStatus.IsOr {
if len(depStatus.Pending) == 0 {
buf.WriteString("Status=AllFailed")
} else {
buf.WriteString("Status=WaitForAny")
}
} else {
buf.WriteString("Status=SomeFailed")
}
}
case *protos.DependencyStatus_InfinitePast:
// must be AND
if depStatus.GetInfinitePast() {
buf.WriteString("Status=WaitForAll")
}
}
return buf.String()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "output.go" -path "*/ccontrol/*" | head -5

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 99


🏁 Script executed:

wc -l internal/ccontrol/output.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 101


🏁 Script executed:

sed -n '689,759p' internal/ccontrol/output.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 2042


🏁 Script executed:

fd -e proto | xargs rg "message DependencyCondition" -A 10 2>/dev/null

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 527


🏁 Script executed:

fd -type f -name "*.go" | xargs rg "func SecondTimeFormat" -B 2 -A 5 2>/dev/null | head -30

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 599


🏁 Script executed:

gofmt -d internal/ccontrol/output.go | head -100

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 113


🏁 Script executed:

fd -e go -path "*/ccontrol/*" -type f | xargs rg "formatDependencyStatus|TestFormatDependency" 2>/dev/null

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 448


🏁 Script executed:

sed -n '715,759p' internal/ccontrol/output.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 1322


🏁 Script executed:

find . -name "*.md" -o -name "*.txt" | xargs rg "DependencyStatus|dependency.*status" -i 2>/dev/null | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 747


🏁 Script executed:

find . -name "*.go" | xargs rg "DependencyStatus" -B 2 -A 2 2>/dev/null | grep -i "test\|spec\|comment" | head -30

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 139


🏁 Script executed:

rg "message DependencyStatus" protos/ -A 30

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 1479


🏁 Script executed:

python3 << 'EOF'
import import math
# math.MaxInt64 = 2^63 - 1 = 9223372036854775807
max_int64 = 2**63 - 1
max_uint64 = 2**64 - 1
print(f"math.MaxInt64: {max_int64}")
print(f"math.MaxUint64: {max_uint64}")
print(f"Overflow risk: uint64 values > {max_int64} will overflow")
EOF

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 156


🏁 Script executed:

rg "delay_seconds|DelaySeconds" . --type go -B 3 -A 3 2>/dev/null | head -50

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 962


🏁 Script executed:

sed -n '/^func SecondTimeFormat/,/^func [A-Z]/p' internal/util/string.go | head -40

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 571


🏁 Script executed:

rg "if\s*\(" internal/ccontrol/output.go | head -10

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 123


🏁 Script executed:

find . -name "*.yml" -o -name "*.yaml" | xargs cat 2>/dev/null | grep -i "gofmt\|format" | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 355


Fix type conversion overflow and gofmt formatting issue

Two issues require attention:

  • Type conversion overflow in formatDependencyCondition: cond.DelaySeconds is uint64 while util.SecondTimeFormat expects int64. Any delay value exceeding math.MaxInt64 (9,223,372,036,854,775,807 seconds) will overflow to a negative value and produce malformed output (e.g., negative days). Add bounds checking before conversion: if cond.DelaySeconds > math.MaxInt64 { /* handle large value */ } or use a fallback representation.
  • gofmt style violation: The condition if(depStatus.IsOr || len(depStatus.Pending) == 0) must have a space after if. The CI pipeline enforces gofmt compliance, so run gofmt -w internal/ccontrol/output.go before merging.

The status mapping logic in formatDependencyStatus is complex and would benefit from validation against the ctld-side specification, though the code logic appears internally consistent.

🤖 Prompt for AI Agents
internal/ccontrol/output.go lines 689-759: fix two issues — first, prevent
uint64->int64 overflow in formatDependencyCondition by checking if
cond.DelaySeconds > math.MaxInt64 before converting; if it is, use a safe
fallback representation (e.g., cap to math.MaxInt64, or return a special string
like "huge" or format seconds directly) and add the required import for math;
second, fix gofmt spacing by adding a space after the if in
formatDependencyStatus (change "if(depStatus.IsOr ..." to "if (depStatus.IsOr
..." or better "if depStatus.IsOr || len(depStatus.Pending) == 0") and run gofmt
-w internal/ccontrol/output.go before committing.

Comment on lines 1108 to 1308
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
log.Fatal(err)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use consistent error handling pattern.

This code uses log.Fatal(err) which exits immediately without proper error handling. Other validation errors in this function return wrapped errors (e.g., util.NewCraneErr or util.WrapCraneErr). Use the same pattern for consistency.

Apply this diff:

 	if FlagDependency != "" {
 		err := util.SetTaskDependencies(task, FlagDependency)
 		if err != nil {
-			log.Fatal(err)
+			return util.WrapCraneErr(util.ErrorCmdArg, "Invalid argument: %s", err)
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
log.Fatal(err)
}
}
if FlagDependency != "" {
err := util.SetTaskDependencies(task, FlagDependency)
if err != nil {
return util.WrapCraneErr(util.ErrorCmdArg, "Invalid argument: %s", err)
}
}
🤖 Prompt for AI Agents
In internal/crun/crun.go around lines 1108-1113, replace the direct
log.Fatal(err) call with the repository's consistent error-wrapping/return
pattern: capture the error from util.SetTaskDependencies and return a wrapped
Crane error (e.g., return util.WrapCraneErr(err, "setting task dependencies") or
similar existing wrapper used elsewhere) so the function returns a propagated,
wrapped error instead of exiting the process.


uint32 gid = 14; // egid

Dependencies dependencies = 15;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the current state of TaskToCtld in PublicDefs.proto
rg -A 30 "message TaskToCtld" protos/PublicDefs.proto | head -60

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 776


🏁 Script executed:

# Check git history to see what was previously at field tag 15
cd protos && git log --oneline -p -- PublicDefs.proto | grep -A 5 -B 5 "= 15;" | head -100

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 2796


🏁 Script executed:

# Also check if there are any recent commits affecting field 15 in TaskToCtld
git log --all --pretty=format:"%h %s" -- protos/PublicDefs.proto | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 953


🏁 Script executed:

# Check the state of PublicDefs.proto before the dependency commit
git show e4695a0^:protos/PublicDefs.proto | grep -A 40 "message TaskToCtld"

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 108


🏁 Script executed:

# Also verify if there are any other commits that might have used tag 15 in TaskToCtld
git log --all -p -- protos/PublicDefs.proto | grep -B 10 "TaskToCtld" | grep "= 15;" | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

# Check if there's a CHANGELOG or release notes that might indicate field history
find . -type f \( -name "CHANGELOG*" -o -name "RELEASE*" -o -name "*.md" \) | grep -iE "change|release|history" | head -10

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

# Check for any documentation about proto versioning or compatibility
rg -l "tag.*15|field.*15|compatibility|breaking" --type md | head -10

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 218


🏁 Script executed:

# Check if there are git tags that might represent releases
git tag | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

# Check if there's any released version information in git
git branch -a | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 190


Verify tag 15 in TaskToCtld was not used in previous releases before assigning dependencies

Adding Dependencies dependencies = 15; is wire-compatible only if field number 15 was never assigned to a different field in any released version. The current codebase shows tag 15 is newly assigned to dependencies, but confirm against your project's release history and language-specific proto bindings that tag 15 was not previously used in TaskToCtld. Reusing a tag that held a different field in any shipped release would be a breaking change.

🤖 Prompt for AI Agents
In protos/PublicDefs.proto around line 186, the new field "Dependencies
dependencies = 15;" may reuse tag 15 from prior releases; verify that tag 15 was
never previously assigned in any shipped version of TaskToCtld by searching git
history (git log/blame), checking released tags/branches, and inspecting
language-specific generated protobuf bindings and published artifacts
(packages/jars/wheels) for any prior use of field number 15; if tag 15 was ever
used, pick an unused field number instead (or restore the old semantics), and if
you must permanently avoid reuse add a reserved 15 line to the proto for past
uses and choose a new number, then regenerate language bindings and update
changelog/release notes accordingly.

Comment on lines 480 to 483
/* 24-28 Reserved */

// Dynamic task information
optional DependencyStatus dependency_status = 29;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd protos && cat PublicDefs.proto | grep -n "message TaskInfo" -A 100 | head -150

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 3333


🏁 Script executed:

cd protos && git log --oneline -20 -- PublicDefs.proto

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 94


🏁 Script executed:

cd protos && git show e4695a0 -- PublicDefs.proto | head -100

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 2749


🏁 Script executed:

cd protos && git log --all --oneline | tail -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 791


🏁 Script executed:

cd protos && git log --all --oneline -- PublicDefs.proto

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 3183


🏁 Script executed:

cd protos && git show e4695a0^:protos/PublicDefs.proto | grep -n "message TaskInfo" -A 60 | head -80

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 108


🏁 Script executed:

cd protos && git show e4695a0 --stat

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 7514


🏁 Script executed:

cd protos && git show 5788342:protos/PublicDefs.proto | grep -n "message TaskInfo" -A 60 | head -80

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 1999


🏁 Script executed:

cd protos && git log --all -p -- protos/PublicDefs.proto | grep -B 5 -A 5 "Reserved" | head -60

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

cd protos && git blame -L 449,449 5788342:protos/PublicDefs.proto

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 140


🏁 Script executed:

cd protos && for commit in 04ee4e9 bd29cfb 3fd94f1 692d3d9 8e7e6a9; do
  echo "=== Commit $commit ==="
  git show $commit:protos/PublicDefs.proto 2>/dev/null | grep -A 30 "message TaskInfo" | grep -E "(Reserved|optional|bool held|TaskStatus status)" | head -5
done

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 313


🏁 Script executed:

cd protos && git diff 5788342 e4695a0 -- protos/PublicDefs.proto | grep -A 20 -B 5 "Reserved\|dependency_status" | head -60

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

cd protos && git show e4695a0:protos/PublicDefs.proto | grep -B 3 -A 3 "24-28 Reserved"

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 290


Verify tag 29 was never used in production before reassigning it

TaskInfo now changes the reserved range from 26-29 (in commit 5788342) to 24-28 and assigns tag 29 to optional DependencyStatus dependency_status. While tag 29 was previously marked as reserved, this change should be validated:

  • Tags 24-25 are being removed from reserved (previously part of 26-29 range)
  • Tag 29 is transitioning from reserved to active use
  • Reserved tags are currently declared only as a comment (/* 24-28 Reserved */) rather than using proper proto3 syntax (reserved 24, 25, 26, 27, 28;)

Recommend either: (1) confirming tag 29 was never actually used in any released version, or (2) using formal reserved declarations in the proto file to prevent accidental reuse in the future.

🤖 Prompt for AI Agents
In protos/PublicDefs.proto around lines 480 to 483, TaskInfo's reserved range
was changed from 26-29 to 24-28 and tag 29 was assigned to optional
DependencyStatus; verify that tag 29 was never used in any released/production
descriptor sets or wire data before assigning it (check historical commits,
released .proto artifacts, compiled descriptors, and any running services), and
either (A) confirm no production usage and update the comment to a proper proto
reserved declaration for any tags that should remain protected, or (B) if tag 29
was used, revert the assignment and instead add a formal reserved 24,25,26,27,28
(and 29 if needed) declaration to prevent accidental reuse.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (8)
internal/util/err.go (1)

203-204: Fix the gofmt formatting issue.

The indentation on line 203 uses tabs instead of spaces, which is inconsistent with other entries and causes the gofmt pipeline failure. Run gofmt -w internal/util/err.go to fix.

internal/calloc/cmd.go (1)

49-49: Fix the gofmt formatting issue.

The declaration has inconsistent spacing. Run gofmt -w internal/calloc/cmd.go to fix.

internal/cbatch/cmd.go (1)

64-64: Fix the gofmt formatting issue.

Run gofmt -w internal/cbatch/cmd.go to fix the formatting.

internal/cbatch/cbatch.go (1)

196-200: Fix the indentation issue.

The code inside the case block is not properly indented, causing the gofmt pipeline failure.

Apply this diff:

 		case "--dependency", "-d":
-		err := util.SetTaskDependencies(task, arg.val)
-		if err != nil {
+			err := util.SetTaskDependencies(task, arg.val)
+			if err != nil {
 				return nil, fmt.Errorf("invalid argument: failed to set dependencies: %w", err)
-		}
+			}
protos/PublicDefs.proto (2)

186-186: Verify field number 15 was never used in prior releases.

Adding Dependencies dependencies = 15; is only safe if field number 15 was never assigned to a different field in any released version of TaskToCtld. Reusing a field number that held a different field in any shipped release would break wire compatibility with older clients/servers. Verify against your project's release history that tag 15 was not previously used.

Run the following script to check the git history for prior usage of field number 15 in TaskToCtld:

#!/bin/bash
# Description: Search git history for any prior assignment of field number 15 in TaskToCtld

# Search through all commits for changes to TaskToCtld around field 15
git log --all -p -- protos/PublicDefs.proto | grep -B 10 -A 2 "= 15;" | grep -B 10 -A 2 "TaskToCtld" | head -50

# Also check if there are any git tags (releases) we should verify against
echo "=== Git tags/releases ==="
git tag -l | head -20

479-482: Verify tag 29 was never used before reassigning from reserved range.

The reserved range was changed from 26-29 to 25-28, and tag 29 is now assigned to optional DependencyStatus dependency_status. This is only safe if:

  1. Tag 29 was never used in any released version before being reserved
  2. No production systems have descriptors or wire data using tag 29

Additionally, consider using proper proto3 reserved syntax instead of comments for future protection:

reserved 25, 26, 27, 28;

Run the following script to check tag 29 usage history:

#!/bin/bash
# Description: Verify tag 29 was never used in TaskInfo before being reserved

# Check git history for any prior usage of tag 29 in TaskInfo
git log --all -p -- protos/PublicDefs.proto | grep -B 15 -A 2 "= 29;" | grep -B 15 -A 2 "TaskInfo" | head -100

# Check when the reserved range was introduced
git log --all -p -- protos/PublicDefs.proto | grep -B 5 -A 5 "Reserved" | grep -B 5 -A 5 "26-29\|25-28" | head -50
internal/ccontrol/output.go (2)

721-731: Fix type conversion overflow.

Line 727 converts cond.DelaySeconds (uint64) to int64 for util.SecondTimeFormat, which will overflow for values exceeding math.MaxInt64 (9,223,372,036,854,775,807 seconds, approximately 292 billion years). Add bounds checking before conversion.

Apply this diff:

 func formatDependencyCondition(cond *protos.DependencyCondition) string {
 	if cond == nil {
 		return ""
 	}
 	depTypeStr := formatDependencyType(cond.Type)
 	if cond.DelaySeconds > 0 {
-		delayStr := util.SecondTimeFormat(int64(cond.DelaySeconds))
+		var delayStr string
+		if cond.DelaySeconds > math.MaxInt64 {
+			delayStr = fmt.Sprintf("%ds", cond.DelaySeconds)
+		} else {
+			delayStr = util.SecondTimeFormat(int64(cond.DelaySeconds))
+		}
 		return fmt.Sprintf("%s:%d+%s", depTypeStr, cond.JobId, delayStr)
 	}
 	return fmt.Sprintf("%s:%d", depTypeStr, cond.JobId)
 }

733-776: Fix gofmt formatting issue.

Line 752 has a gofmt violation: if(depStatus.IsOr || len(depStatus.Pending) == 0) must have a space after if. The CI pipeline is failing due to this formatting issue. Run gofmt -w internal/ccontrol/output.go to fix.

Apply this diff:

-	if(depStatus.IsOr || len(depStatus.Pending) == 0) {
+	if depStatus.IsOr || len(depStatus.Pending) == 0 {
 		buf.WriteString(fmt.Sprintf("Status=ReadyAfter %s", readyTime.In(time.Local).Format("2006-01-02 15:04:05")))
 	} else {
 		buf.WriteString("Status=WaitForAll")
 	}
🧹 Nitpick comments (1)
internal/util/string.go (1)

1476-1480: Consider tightening the job list validation regex.

The regex ^[\d+:a-zA-Z]+$ is quite permissive and would match strings without any digits (e.g., "abc"). While the subsequent jobPattern regex would fail to extract valid job IDs, the error message at line 1496 ("no valid job IDs found") is less informative than the one at line 1479 about format. Consider validating that at least one digit exists, or rely solely on the jobPattern matching.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4695a0 and 47afab6.

📒 Files selected for processing (10)
  • internal/calloc/calloc.go (1 hunks)
  • internal/calloc/cmd.go (2 hunks)
  • internal/cbatch/cbatch.go (2 hunks)
  • internal/cbatch/cmd.go (2 hunks)
  • internal/ccontrol/output.go (2 hunks)
  • internal/crun/cmd.go (2 hunks)
  • internal/crun/crun.go (1 hunks)
  • internal/util/err.go (2 hunks)
  • internal/util/string.go (2 hunks)
  • protos/PublicDefs.proto (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/calloc/calloc.go
  • internal/crun/crun.go
  • internal/crun/cmd.go
🧰 Additional context used
🧬 Code graph analysis (4)
internal/cbatch/cmd.go (1)
internal/crun/cmd.go (1)
  • FlagDependency (46-46)
internal/cbatch/cbatch.go (4)
internal/util/string.go (1)
  • SetTaskDependencies (1447-1523)
internal/calloc/cmd.go (1)
  • FlagDependency (49-49)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/crun/cmd.go (1)
  • FlagDependency (46-46)
internal/calloc/cmd.go (2)
internal/cbatch/cmd.go (1)
  • FlagDependency (64-64)
internal/crun/cmd.go (1)
  • FlagDependency (46-46)
internal/ccontrol/output.go (1)
internal/util/string.go (1)
  • SecondTimeFormat (438-452)
🪛 GitHub Actions: Go Code Quality Check
internal/cbatch/cmd.go

[error] 1-1: gofmt formatting check failed. The file is not properly formatted according to gofmt.

internal/cbatch/cbatch.go

[error] 1-1: gofmt formatting check failed. The file is not properly formatted according to gofmt.

internal/calloc/cmd.go

[error] 1-1: gofmt formatting check failed. The file is not properly formatted according to gofmt.

internal/util/err.go

[error] 1-1: gofmt formatting check failed. The file is not properly formatted according to gofmt.

internal/ccontrol/output.go

[error] 1-1: gofmt formatting check failed. The file is not properly formatted according to gofmt.

🔇 Additional comments (9)
internal/util/err.go (1)

176-176: LGTM on the simplified error message.

The updated message for ERR_BEYOND_TASK_ID is more concise and accurately describes the error condition.

internal/calloc/cmd.go (1)

107-107: LGTM on the new dependency flag.

The flag is correctly wired with -d shorthand and appropriate description, consistent with other modules.

internal/cbatch/cmd.go (1)

159-159: LGTM on the dependency flag registration.

Consistent with the pattern used in calloc and crun modules.

internal/cbatch/cbatch.go (1)

341-346: LGTM on CLI dependency handling.

The CLI flag handling correctly follows the established pattern where command-line arguments take precedence over script values.

internal/util/string.go (1)

637-645: LGTM on duplicate dependency check.

The validation correctly prevents duplicate task IDs in the dependency list.

internal/ccontrol/output.go (2)

582-588: LGTM! Clean integration of dependency status output.

The dependency status output is appropriately gated by nil-check and empty-string check, ensuring it only prints when meaningful information is available. This follows the pattern used for other optional fields in the job details output.


706-719: LGTM! Straightforward enum-to-string mapping.

The implementation correctly maps all defined DependencyType enum values to their string representations and provides a safe fallback for unexpected values.

protos/PublicDefs.proto (2)

135-162: LGTM! Well-designed dependency type definitions.

The new protobuf messages provide a comprehensive dependency system:

  • DependencyType enum covers standard scheduling dependency types
  • DependencyCondition includes job ID, type, and optional delay
  • Dependencies supports both OR and AND semantics via is_or flag
  • DependencyStatus oneof design elegantly represents three states: ready at a specific time, infinite future (blocked), or infinite past (already satisfied)

726-727: LGTM! New error codes for dependency feature.

The two new error codes are appropriately added:

  • ERR_MISSING_DEPENDENCY = 85: For handling missing/invalid dependency references
  • ERR_DB_INSERT_FAILED = 86: For database insertion failures

The sequential numbering after the existing ERR_STEP_RES_BEYOND = 84 maintains enum consistency. Adding new error codes at the end of an enum is a safe, backward-compatible change.

Comment on lines 1447 to 1523
func SetTaskDependencies(task *protos.TaskToCtld, depStr string) error {
depStr = strings.TrimSpace(depStr)

hasComma := strings.Contains(depStr, ",")
hasQuestion := strings.Contains(depStr, "?")
if hasComma && hasQuestion {
return fmt.Errorf("cannot use both ',' and '?' in the dependency string")
}

sep := ","
if hasQuestion {
sep = "?"
}

task.Dependencies = &protos.Dependencies{
IsOr: hasQuestion,
}

// Regex: (type):(job_id[+delay][:job_id[+delay]]...)
depPattern := regexp.MustCompile(`^(after|afterok|afternotok|afterany):(.+)$`)
jobPattern := regexp.MustCompile(`(\d+)(?:\+([0-9a-zA-Z]+))?`)

depStrList := strings.Split(depStr, sep)
for _, subDepStr := range depStrList {
matches := depPattern.FindStringSubmatch(subDepStr)
if matches == nil {
return fmt.Errorf("unrecognized dependency string: %s", subDepStr)
}

depTypeStr, jobsStr := matches[1], matches[2]

if !regexp.MustCompile(`^[\d+:a-zA-Z]+$`).MatchString(jobsStr) {
return fmt.Errorf("invalid job list format in '%s': should only contain job_id[+delay] separated by ':'", jobsStr)
}

var depType protos.DependencyType
switch depTypeStr {
case "after":
depType = protos.DependencyType_AFTER
case "afterok":
depType = protos.DependencyType_AFTER_OK
case "afternotok":
depType = protos.DependencyType_AFTER_NOT_OK
case "afterany":
depType = protos.DependencyType_AFTER_ANY
}

jobMatches := jobPattern.FindAllStringSubmatch(jobsStr, -1)
if jobMatches == nil {
return fmt.Errorf("no valid job IDs found in: %s", subDepStr)
}

for _, jobMatch := range jobMatches {
jobId, _ := strconv.ParseUint(jobMatch[1], 10, 32)
var delaySeconds uint64 = 0
if jobMatch[2] != "" {
delayStr := jobMatch[2]
// If delayStr contains only digits, treat it as minutes by default
if regexp.MustCompile(`^\d+$`).MatchString(delayStr) {
delayStr = delayStr + "m"
}
seconds, err := ParseRelativeTime(delayStr)
if err != nil {
return fmt.Errorf("invalid delay format '%s' in dependency: %v", jobMatch[2], err)
}
delaySeconds = uint64(seconds)
}

task.Dependencies.Deps = append(task.Dependencies.Deps, &protos.DependencyCondition{
JobId: uint32(jobId),
Type: depType,
DelaySeconds: delaySeconds,
})
}
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for SetTaskDependencies references and tests
rg -n "SetTaskDependencies" --type go -g '!vendor/*'

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 504


🏁 Script executed:

#!/bin/bash
# Search for test files related to SetTaskDependencies or string.go tests
find . -name "*test*.go" -type f | grep -E "(string|util)" | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Also search for any test references to dependency parsing
rg -n "SetTaskDependencies|dependency.*test|test.*dependency" --type go -i | head -30

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 504


🏁 Script executed:

#!/bin/bash
# Check if there's a string_test.go file specifically
find . -name "string_test.go" -type f

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Let's look at the complete function and verify the parsing logic
sed -n '1447,1523p' internal/util/string.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 2393


🏁 Script executed:

#!/bin/bash
# Search for any documentation about dependency format in the codebase
rg -n "dependency.*format|delay.*format|job.*id.*format" --type go -i | head -20

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 785


🏁 Script executed:

#!/bin/bash
# Check if there are any README or docs files that describe the dependency format
find . -type f \( -name "README*" -o -name "*.md" -o -name "DOCS*" \) | xargs grep -l "dependency\|delay" 2>/dev/null | head -10

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check for any documentation or comments above the SetTaskDependencies function
sed -n '1420,1450p' internal/util/string.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 975


🏁 Script executed:

#!/bin/bash
# Check the calling sites for usage patterns and documentation
sed -n '1300,1310p' internal/crun/crun.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 228


🏁 Script executed:

#!/bin/bash
# Check another calling site for context
sed -n '190,210p' internal/cbatch/cbatch.go

Repository: PKUHPC/CraneSched-FrontEnd

Length of output: 776


Add tests and documentation for dependency parsing behavior.

The function lacks both test coverage and documentation. With no godoc comment or format specification, the expected formats are undocumented despite the function being used across multiple commands (crun, cbatch, calloc). The implementation details—numeric-only delays treated as minutes, comma for AND semantics, question mark for OR semantics—must be tested and documented to prevent regressions and ensure users understand the expected format.

🤖 Prompt for AI Agents
internal/util/string.go lines 1447-1523: the SetTaskDependencies function is
undocumented and untested; add a godoc comment immediately above the function
that clearly specifies the accepted dependency string grammar, examples (e.g.
"after:123", "afterok:123+5m:124", numeric-only delay means minutes, ',' = AND,
'?' = OR) and the semantics of values and errors, then create unit tests under
internal/util with table-driven cases that cover: valid single and multiple
dependencies, both separators (',' and '?'), numeric-only delays treated as
minutes, explicit time units, invalid formats (bad characters, unknown
dependency types), missing job IDs, parse errors from ParseRelativeTime, and
mixed separators error; ensure tests assert the produced protos.Dependencies
fields (IsOr, Deps with JobId, Type, DelaySeconds) and run go test to confirm
behavior.

Copy link
Contributor

@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

♻️ Duplicate comments (1)
internal/ccontrol/output.go (1)

721-731: Fix uint64 to int64 overflow risk.

Line 727 casts cond.DelaySeconds (uint64) directly to int64 for util.SecondTimeFormat. Any delay exceeding math.MaxInt64 (≈292 billion years, or 9,223,372,036,854,775,807 seconds) will overflow to a negative value and produce malformed output with negative days.

🔎 Apply this diff to add bounds checking:
 func formatDependencyCondition(cond *protos.DependencyCondition) string {
 	if cond == nil {
 		return ""
 	}
 	depTypeStr := formatDependencyType(cond.Type)
 	if cond.DelaySeconds > 0 {
-		delayStr := util.SecondTimeFormat(int64(cond.DelaySeconds))
+		var delayStr string
+		if cond.DelaySeconds > math.MaxInt64 {
+			delayStr = fmt.Sprintf("%d seconds", cond.DelaySeconds)
+		} else {
+			delayStr = util.SecondTimeFormat(int64(cond.DelaySeconds))
+		}
 		return fmt.Sprintf("%s:%d+%s", depTypeStr, cond.JobId, delayStr)
 	}
 	return fmt.Sprintf("%s:%d", depTypeStr, cond.JobId)
 }
🧹 Nitpick comments (1)
internal/calloc/cmd.go (1)

107-107: LGTM! Flag registration is correct and consistent.

The flag registration follows the established pattern and the short flag -d does not conflict with existing flags.

Regarding the past review comment about gofmt formatting: the current code appears properly formatted. Please verify by running gofmt -d internal/calloc/cmd.go to confirm the formatting issue has been resolved.

💡 Optional enhancement

Consider making the description more informative by adding an example:

-	RootCmd.Flags().StringVarP(&FlagDependency, "dependency", "d", "", "Conditions for job to execute")
+	RootCmd.Flags().StringVarP(&FlagDependency, "dependency", "d", "", "Conditions for job to execute (e.g., afterok:123,afterany:456)")

This helps users understand the expected format without consulting documentation.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47afab6 and 6989a4c.

📒 Files selected for processing (5)
  • internal/calloc/cmd.go (2 hunks)
  • internal/cbatch/cbatch.go (2 hunks)
  • internal/cbatch/cmd.go (2 hunks)
  • internal/ccontrol/output.go (2 hunks)
  • internal/util/err.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/cbatch/cmd.go
  • internal/cbatch/cbatch.go
🧰 Additional context used
🧬 Code graph analysis (2)
internal/calloc/cmd.go (1)
internal/crun/cmd.go (1)
  • FlagDependency (46-46)
internal/ccontrol/output.go (1)
internal/util/string.go (1)
  • SecondTimeFormat (438-452)
🔇 Additional comments (6)
internal/calloc/cmd.go (1)

45-49: LGTM! Variable declarations follow established patterns.

The variable declarations are properly formatted and consistent with the rest of the file.

internal/util/err.go (2)

176-176: LGTM!

The error message clarification removes ambiguity and provides a more precise description of the condition.


203-204: LGTM!

The new error codes are well-defined with clear, user-friendly messages that align with the dependency subsystem requirements.

internal/ccontrol/output.go (3)

582-588: LGTM!

The dependency output integration is well-structured with appropriate nil checks and only displays when dependency status is present and non-empty.


706-719: LGTM!

The dependency type formatting is straightforward and handles all documented dependency types with a sensible fallback for unknown values.


733-776: Code is properly formatted and logically correct.

The dependency status formatting function uses consistent tab indentation, proper operator spacing, and follows Go conventions. The logic correctly handles the three ReadyTimeType cases (ReadyTime, InfiniteFuture, InfinitePast) with appropriate status strings based on the IsOr flag and pending dependency count. No formatting or logical issues found.

Copy link
Contributor

@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

♻️ Duplicate comments (2)
internal/util/string.go (2)

1454-1533: Add comprehensive godoc comment to document the dependency string format.

The function is exported and called from multiple commands (calloc, cbatch, crun) but lacks documentation. Users and maintainers need to understand the expected format and semantics without reading the implementation.

Based on learnings, this was flagged in previous reviews. The dependency string grammar should document:

  • Accepted dependency types (after, afterok, afternotok, afterany)
  • Job ID and delay format (jobid[+delay])
  • Separator semantics (',' for AND, '?' for OR)
  • Delay units (numeric-only defaults to minutes, or explicit units like m/h/d/w)
  • Examples (e.g., "afterok:123+5m:124", "after:100,afterok:101")
Example godoc template
+// SetTaskDependencies parses a dependency specification string and populates task.Dependencies.
+//
+// Format: type:jobid[+delay][:jobid[+delay]]...
+//   - type: after, afterok, afternotok, afterany
+//   - jobid: numeric job ID (required)
+//   - delay: optional delay; numeric values default to minutes, or specify units (e.g., 5m, 1h, 2d)
+//   - Multiple dependencies: separated by ',' (AND) or '?' (OR), but not both
+//
+// Examples:
+//   - "afterok:123" - wait for job 123 to complete successfully
+//   - "afterok:123+5m:124" - wait for jobs 123 and 124, with 5-minute delay after 123
+//   - "after:100,afterok:101" - AND: wait for job 100 (any state) AND job 101 (success)
+//   - "afterok:200?afterok:201" - OR: wait for job 200 OR job 201 to succeed
+//
+// Returns an error if the format is invalid or if both ',' and '?' are used.
 func SetTaskDependencies(task *protos.TaskToCtld, depStr string) error {

1454-1533: Tests for SetTaskDependencies are still missing.

The function lacks unit test coverage for various input formats, edge cases, and error conditions.

Based on learnings, this was flagged in previous reviews. Consider table-driven tests covering:

  • Valid single and multiple dependencies
  • Both separators (',' and '?')
  • Numeric-only delays (should default to minutes)
  • Explicit time units (m, h, d, w)
  • Invalid formats (bad characters, unknown types)
  • Missing job IDs
  • Parse errors from ParseRelativeTime
  • Mixed separator error
  • Zero job IDs (after adding validation)

Verify that the produced protos.Dependencies struct has correct IsOr flag and Deps entries with expected JobId, Type, and DelaySeconds.

🧹 Nitpick comments (1)
internal/util/string.go (1)

1507-1510: Good: Error handling for job ID parsing is now present, but add zero validation.

The error from ParseUint is now properly captured and returned, addressing the previous review comment. However, job ID 0 may be invalid in this context and should be explicitly rejected.

Suggested zero validation
 		for _, jobMatch := range jobMatches {
 			jobId, err := strconv.ParseUint(jobMatch[1], 10, 32)
 			if err != nil {
 				return fmt.Errorf("invalid job ID '%s' in dependency: %v", jobMatch[1], err)
 			}
+			if jobId == 0 {
+				return fmt.Errorf("invalid job ID: 0 is not allowed in dependencies")
+			}
 			var delaySeconds uint64 = 0
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ae94df and 52b382a.

📒 Files selected for processing (1)
  • internal/util/string.go
🔇 Additional comments (2)
internal/util/string.go (2)

176-204: LGTM: Compound duration parsing is well-implemented.

The enhancement correctly handles multi-unit durations like "1h30m" by detecting the compound format, extracting value-unit pairs, and accumulating the total seconds. The case-insensitive unit matching and clear error messages for invalid units are good practices.


644-652: LGTM: Duplicate task ID validation is correct.

The validation correctly uses a map to detect duplicate job IDs in dependencies with O(1) lookup time. The error message clearly identifies which task ID is duplicated.

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.

2 participants