Skip to content

Simplify run condition APIs - #4269

Open
thomhurst wants to merge 7 commits into
mainfrom
issue-4224-run-conditions
Open

Simplify run condition APIs#4269
thomhurst wants to merge 7 commits into
mainfrom
issue-4224-run-conditions

Conversation

@thomhurst

@thomhurst thomhurst commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • add singular RunIf<T> and a stateful RunIfAttribute base
  • keep RunIfAll and RunIfAny for two-to-four conditions
  • rename IsCI/IsLocal to OnCI/OnLocal
  • remove duplicate operating-system attributes, enum, helper, and obsolete GitHub option
  • migrate build modules, tests, and current documentation

Testing

  • build ModularPipelines.Tests.slnf -c Release (178 existing warnings, 0 errors)
  • RunConditionApiSurfaceTests (2 passed)
  • NewRunConditionAttributeTests (21 passed)
  • build src/ModularPipelines.GitHub/ModularPipelines.GitHub.slnx -c Release (3 warnings, 0 errors)
  • build test/ModularPipelines.Distributed.UnitTests/ModularPipelines.Distributed.UnitTests.csproj -c Release (0 warnings, 0 errors)

Closes #4224

Summary by CodeRabbit

  • New Features

    • Added the unified RunIf<T> syntax for modules with a single run condition.
    • Improved support for combining conditions across operating systems and distributed execution.
    • Added OnCI and OnLocal condition names.
  • Breaking Changes

    • Removed legacy operating-system-specific condition attributes and identifiers.
    • Single-condition RunIfAll<T> and RunIfAny<T> forms are no longer supported.
  • Documentation

    • Updated platform, skipping, migration, and run-condition guidance with the new syntax and built-in conditions.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 5 minutes.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 62c92104-3a32-42a9-850a-9d7716ee0906

📥 Commits

Reviewing files that changed from the base of the PR and between aae6235 and 028c759.

📒 Files selected for processing (16)
  • docs/docs/distributed/capabilities.md
  • docs/docs/how-to/run-conditions.md
  • docs/docs/how-to/skipping.md
  • docs/docs/migrating-to-v3.md
  • src/ModularPipelines.GitHub/PublicAPI.Shipped.txt
  • src/ModularPipelines.GitHub/PublicAPI.Unshipped.txt
  • src/ModularPipelines/Attributes/OperatingSystemConditions.cs
  • src/ModularPipelines/Conditions/OnFreeBSD.cs
  • src/ModularPipelines/Distributed/Master/DistributedWorkPublisher.cs
  • src/ModularPipelines/PublicAPI.Shipped.txt
  • src/ModularPipelines/PublicAPI.Unshipped.txt
  • test/ModularPipelines.Distributed.UnitTests/Master/DistributedModuleExecutorTests.cs
  • test/ModularPipelines.UnitTests/Api/RunConditionApiSurfaceTests.cs
  • test/ModularPipelines.UnitTests/Attributes/OperatingSystemConditionsTests.cs
  • test/ModularPipelines.UnitTests/Engine/DependencyGraphExporterTests.cs
  • test/ModularPipelines.UnitTests/Engine/ModuleConditionHandlerTests.cs
📝 Walkthrough

Walkthrough

The PR adds the singular RunIf<T> API, preserves multi-condition RunIfAll and RunIfAny forms, renames built-in conditions, removes legacy operating-system APIs, updates distributed planning, and migrates modules, documentation, and tests.

Changes

RunIf condition API migration

Layer / File(s) Summary
Condition contracts and operating-system discovery
src/ModularPipelines/Attributes/*, src/ModularPipelines/Conditions/*, src/ModularPipelines/OperatingSystemIdentifier.cs
Adds RunIfAttribute and RunIfAttribute<T>. Removes single-condition grouped attributes and legacy operating-system condition types. Renames IsCI and IsLocal.
Condition evaluation and distributed planning
src/ModularPipelines/Engine/ModuleConditionHandler.cs
Recognizes RunIf, updates skip messages, and defers operating-system conditions on distributed masters.
Module and pipeline integration
src/ModularPipelines.Build/Modules/*, src/ModularPipelines.GitHub/PipelineWriters/GitHubPipelineFileWriterOptions.cs
Migrates build modules to RunIf<On...> and removes RunnerOperatingSystem.
Condition documentation
docs/docs/distributed/capabilities.md, docs/docs/how-to/*, docs/docs/migrating-to-v3.md
Documents the singular condition API, renamed built-in conditions, and capability-based platform examples.
API, engine, and integration tests
test/ModularPipelines.*/*
Updates condition declarations and assertions. Adds API-surface checks and distributed alternative-platform planning tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to aae62

This PR adds public condition APIs and changes distributed operating-system condition planning. The current head still lacks required API-baseline entries and can incorrectly skip modules before an eligible worker evaluates them, so these issues should be fixed or explicitly accepted before merging.

Sequence Diagram(s)

sequenceDiagram
  participant DistributedMaster
  participant ModuleConditionHandler
  participant OperatingSystemConditions
  participant Worker
  DistributedMaster->>ModuleConditionHandler: Plan module conditions
  ModuleConditionHandler->>OperatingSystemConditions: Inspect operating-system targets
  OperatingSystemConditions-->>ModuleConditionHandler: Return condition targets
  ModuleConditionHandler-->>DistributedMaster: Defer unresolved OS conditions
  Worker->>ModuleConditionHandler: Evaluate conditions on worker
Loading

Poem

A rabbit reviews the RunIf trail
New condition names hop without fail
Linux and Windows capabilities glow
Distributed plans defer what they know
Tests guard each API door
Hops away, review complete once more

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 75 functions across 32 files. (4 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: simplifying the run-condition APIs.
Linked Issues check ✅ Passed The changes satisfy issue #4224: they add the singular RunIf API and base class, retain multi-condition RunIfAll and RunIfAny APIs, rename IsCI and IsLocal, remove obsolete operating-system APIs an…
Out of Scope Changes check ✅ Passed The changes are within scope for issue #4224. Documentation, build modules, tests, distributed-pipeline handling, and API-surface updates all support the run-condition API migration and its required b…
Full details: Linked Issues check

Explanation

The changes satisfy issue #4224: they add the singular RunIf<T> API and base class, retain multi-condition RunIfAll and RunIfAny APIs, rename IsCI and IsLocal, remove obsolete operating-system APIs and the enum, remove the obsolete GitHub option, and update modules, tests, and documentation.

Full details: Out of Scope Changes check

Explanation

The changes are within scope for issue #4224. Documentation, build modules, tests, distributed-pipeline handling, and API-surface updates all support the run-condition API migration and its required behavior.

Full details: Docstring Coverage

Explanation

Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 75 functions across 32 files. (4 skipped: 4 unsupported.)

✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-4224-run-conditions

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.

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown

Greptile Summary

The PR simplifies the run-condition API while updating condition planning, distributed OS capability inference, public API baselines, repository modules, tests, and documentation.

  • Adds singular RunIf<T> and a stateful RunIfAttribute base.
  • Retains grouped RunIfAll and RunIfAny forms for two-to-four conditions.
  • Replaces IsCI/IsLocal with OnCI/OnLocal and adds OnFreeBSD.
  • Removes duplicate operating-system APIs and the obsolete GitHub runner OS option.
  • Migrates existing modules, tests, documentation, and public API declarations.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the eligible follow-up review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
src/ModularPipelines/Attributes/RunIfAttribute.cs Introduces the singular generic run-condition attribute and directly delegates evaluation to its condition.
src/ModularPipelines/Attributes/OperatingSystemConditions.cs Extends OS capability inference and impossible-combination detection for singular, grouped, alternative, and FreeBSD conditions.
src/ModularPipelines/Engine/ModuleConditionHandler.cs Integrates the singular condition API into runtime and planning evaluation, including distributed-master deferral.
src/ModularPipelines/Distributed/Master/DistributedWorkPublisher.cs Aggregates grouped operating-system alternatives before publishing distributed capability requirements.
src/ModularPipelines.GitHub/PipelineWriters/GitHubPipelineFileWriterOptions.cs Removes the obsolete runner operating-system option from the GitHub pipeline writer API.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Module condition attributes] --> B{Condition form}
    B -->|RunIf T| C[Evaluate one required condition]
    B -->|RunIfAll T1...T4| D[Require every condition]
    B -->|RunIfAny T1...T4| E[Require at least one condition]
    C --> F[Planning and execution handling]
    D --> F
    E --> F
    F --> G[Infer compatible OS capabilities]
    G --> H[Local execution or distributed assignment]
Loading

Reviews (8): Last reviewed commit: "fix(conditions): route OS alternatives" | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 041b23471b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/docs/how-to/run-conditions.md
Comment thread docs/docs/how-to/run-conditions.md

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: Simplify run condition APIs (#4269)

Reviewed the diff introducing singular RunIf<T> / stateful RunIfAttribute, the IsCI/IsLocalOnCI/OnLocal rename, and removal of the duplicate OS-specific attributes/enum/helper and the obsolete GitHub runner-OS option.

What I checked:

  • RunIfAttribute/RunIfAttribute<T> in src/ModularPipelines/Attributes/RunIfAttribute.cs against the removed single-generic RunIfAllAttribute<T>/RunIfAnyAttribute<T> — evaluation semantics (cancellation check, then direct evaluate) are preserved.
  • ModuleConditionHandler.csGetConditionLogic, IsBuiltInGenericConditionAttribute, IsPlanningConditionAttribute, and the new GetRequiredConditionName helper are consistently wired through for skip-reason messaging ("RunIf<X> not satisfied" vs "RunIfAll<X> not satisfied"), with no duplicated logic.
  • OperatingSystemConditions.cs — the deleted IOperatingSystemConditionAttribute/RunIfOperatingSystemAttribute special-casing has no remaining call sites; OS inference for distributed capability detection correctly covers both RunIf<T> and RunIfAll<T...> via attribute.Logic == ConditionLogic.All.
  • Removed GitHubPipelineFileWriterOptions.RunnerOperatingSystem — confirmed unused elsewhere; runner selection is driven by the Runner string, not this property.
  • Searched src/, test/, and docs/ for leftover references to removed symbols (IsCI, IsLocal, OperatingSystemIdentifier, RunIfOperatingSystemAttribute, SkipIfOperatingSystemAttribute, single-generic RunIfAll<T>/RunIfAny<T>) — none found outside of the historical RELEASE_NOTES_V3.md, which is expected to reference old API names.
  • Migrated build modules (BuildSolutionOnPlatformModule, BuildSolutionsModule, CreateReleaseModule, etc.) and tests consistently swap RunIfAll<OnX>RunIf<OnX> with matching semantics.
  • The new RunConditionApiSurfaceTests.cs explicitly asserts the old types are gone and the new types have the expected shape — a solid regression guard for this exact refactor, and testing described in the PR body (API surface tests, parameterized attribute tests, tool-specific builds) matches what's actually present in the diff.

Assessment: This is a clean, mechanical, well-tested API simplification. No genuine correctness bug, dropped invariant, broken call site, or architectural concern found. No previous review comments exist on this PR to reconcile against.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-29T02:18:23.057913Z 028c759 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@thomhurst

Copy link
Copy Markdown
Owner Author

@claude review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f8638c3318

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines/Attributes/OperatingSystemConditions.cs
@thomhurst

Copy link
Copy Markdown
Owner Author

@claude review

@thomhurst
thomhurst force-pushed the issue-4224-run-conditions branch from f8638c3 to 5599131 Compare August 28, 2026 23:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5599131441

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines/Attributes/OperatingSystemConditions.cs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: Simplify run condition APIs (#4269)

Note: the previously posted claude review on this PR (commit 041b23471b...) was against a commit that's no longer in the branch history (force-pushed/rebased away), so this is a fresh full review of the current diff (26af9b15...55991314), including the newer fix(distributed): route alternative OS conditions commit.

What I checked:

  • RunIfAttribute / RunIfAttribute<T> (src/ModularPipelines/Attributes/RunIfAttribute.cs, RunConditionAttribute.cs) — the new singular condition base is wired consistently alongside RunIfAllAttribute/RunIfAnyAttribute, with Logic => ConditionLogic.All matching existing RunIfAll semantics.
  • ModuleConditionHandler.csGetConditionLogic, IsBuiltInGenericConditionAttribute, IsPlanningConditionAttribute, and the new GetRequiredConditionName helper correctly branch skip-reason messages ("RunIf<X> not satisfied" vs "RunIfAll<X> not satisfied") without duplicating logic.
  • OperatingSystemConditions.cs — the distributed-routing fix extends GetSupportedOperatingSystems(IConditionAttribute) to handle ConditionLogic.Any (union) alongside ConditionLogic.All (intersection), so [RunIfAny<OnLinux, OnMacOS>] now correctly produces an alternative-OS capability (operating-system:linux|macos) instead of being ignored. This is backed by a new test (Alternative_Operating_System_Attributes_Match_Either_Worker in OperatingSystemConditionsTests.cs). The metadata-only overload (GetSupportedOperatingSystems(CustomAttributeData), used for HasImpossibleCombination(Type)) intentionally still only considers RunIf/RunIfAll (via the CustomAttributeMetadata.GetApplicable filter) — consistent, since "impossible combination" detection only makes sense for AND-logic constraints.
  • Removed RunIfAllAttribute<T>/RunIfAnyAttribute<T> single-generic forms, RunIfOperatingSystemAttribute/SkipIfOperatingSystemAttribute, OperatingSystemIdentifier, OperatingSystemHelper — confirmed no remaining call sites anywhere in src/, test/, or current (non-versioned) docs/ via repo-wide grep. docs/versioned_docs/version-3.x/* still references old names, which is correct — those are frozen historical snapshots.
  • IsCI/IsLocalOnCI/OnLocal rename (Conditions/OnCI.cs, OnLocal.cs) — straight renames preserving evaluation logic (CI env var check).
  • Build modules (BuildSolutionOnPlatformModule, BuildSolutionsModule, CreateReleaseModule, PackProjectsModule, etc.) — all consistently migrated RunIfAll<OnX>RunIf<OnX>; grep confirms no leftover single-generic RunIfAll<T>] usages anywhere in the repo.
  • RunConditionApiSurfaceTests.cs (new) locks down the intended API surface (singular RunIf sealed/abstract shape, absence of old single-generic RunIfAll<T>/RunIfAny<T> types, absence of removed OS types) — a solid regression guard for this exact refactor.
  • Docs (run-conditions.md, migrating-to-v3.md, distributed/capabilities.md) updated consistently with the new API and example code.

Assessment: This is a clean, mechanical, well-tested API simplification, and the added distributed-routing fix for RunIfAny OS conditions is correctly scoped and tested. No genuine correctness bug, dropped invariant, broken call site, or architectural concern found.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: Simplify run condition APIs (#4269)

Re-reviewed against the current head (aae62359), which adds one commit since the last claude[bot] review (55991314): "fix(distributed): defer alternative OS checks", addressing the earlier Codex P1 comment about RunIfAny OS conditions not being deferred on the distributed master during evaluation.

What's newly fixed and verified:

  • ModuleConditionHandler.EvaluateAnyPlanningConditions / EvaluateAnyConditions now thread isDistributedMaster through and defer OS-targeted Any conditions (single and grouped) via the new ShouldDeferOperatingSystemCondition helper, matching the existing All-path deferral. Covered by two new tests (Distributed_Master_Does_Not_Filter_Alternative_Os_Condition, Distributed_Master_Graph_Defers_Alternative_Os_Condition).

Outstanding issue (still unaddressed — confirmed by reading current code, not just the diff):

A second, related Codex P1 comment on this PR — comment "Include alternative OS constraints in contradiction checks" on OperatingSystemConditions.cs:85 — has not been fixed by the latest commit, and remains live in the current diff:

  • OperatingSystemConditions.HasImpossibleCombination(Type moduleType) (src/ModularPipelines/Attributes/OperatingSystemConditions.cs#L79-L106) filters attributes with typeof(RunIfAttribute).IsAssignableFrom(type) || typeof(RunIfAllAttribute).IsAssignableFrom(type)RunIfAnyAttribute is never matched, so its OS constraint is silently excluded from the intersection used to detect impossible combinations.
  • Meanwhile DistributedWorkPublisher.CreateAssignment (src/ModularPipelines/Distributed/Master/DistributedWorkPublisher.cs#L37-L42) iterates all IConditionAttributes unfiltered and unions in every OperatingSystemConditions.GetTargets(...) capability, including from RunIfAny.
  • RunIfAttribute<T>, RunIfAllAttribute<T...>, and RunIfAnyAttribute<T...> all use [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] independently, so nothing stops a module from being decorated with both e.g. [RunIfAny<OnLinux, OnMacOS>] and [RunIf<OnWindows>] (ANDed together at the module level).
  • Net effect: for such a module, HasImpossibleCombination reports "not impossible" (since it never sees the RunIfAny constraint), so the distributed master doesn't skip it — but the published assignment ends up requiring both operating-system:linux|macos and windows capabilities simultaneously. CapabilityMatcher.CanExecute requires a worker to satisfy all required capabilities, and GetWorkerCapabilities derives a worker's capability set from a single OS, so no worker can ever satisfy both. The assignment becomes permanently unclaimable instead of the module being cleanly skipped.
  • Suggested fix (as Codex noted): extend HasImpossibleCombination(Type)'s attribute filter to also include RunIfAnyAttribute, unioning its alternatives before intersecting with the other (AND) constraints — mirroring what GetSupportedOperatingSystems(IConditionAttribute) already does for the instance-based overload.

Also still outstanding (lower severity, P2):

Everything else (the RunIf<T>/RunIfAll/RunIfAny API surface, the OnCI/OnLocal rename, removal of the duplicate OS attributes/enum/helper, migrated build modules, tests, and docs) was reviewed in the two prior review rounds on this PR and remains correct — no new concerns found there.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ModularPipelines/Attributes/OperatingSystemConditions.cs (1)

186-186: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Resolve grouped OS conditions during metadata discovery.

GetSupportedOperatingSystems(CustomAttributeData) only accepts direct OS condition types. It returns null for OnUnix.

As a result, [RunIf&lt;OnUnix&gt;] with [RunIf&lt;OnWindows&gt;] does not produce an impossible combination in HasImpossibleCombination(Type), although no worker can satisfy both conditions. Resolve each generic argument through GetSupportedOperatingSystems(Type) so grouped conditions use the same union semantics. Add a category-discovery regression test.

🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@src/ModularPipelines/Attributes/OperatingSystemConditions.cs` at line 186,
Update GetSupportedOperatingSystems(CustomAttributeData) to resolve each generic
argument via GetSupportedOperatingSystems(Type), preserving union semantics for
grouped conditions such as OnUnix and OnWindows so
HasImpossibleCombination(Type) detects impossible combinations. Add a regression
test covering the grouped Unix/Windows conditions during category discovery.
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

Inline comments:
In `@docs/docs/how-to/run-conditions.md`:
- Around line 34-37: Update the evaluation-order documentation around
ModuleConditionHandler to include RunIf alongside RunIfAll, placing it after
SkipIf and before RunIfAny.

In `@docs/docs/how-to/skipping.md`:
- Around line 12-13: Update the attribute conditions list in the skipping
documentation to state that RunIfAll and RunIfAny support two to four
conditions, using either T1 through T4 notation or explicit wording, while
preserving the existing descriptions of the other attributes.

In `@src/ModularPipelines/Attributes/RunConditionAttribute.cs`:
- Line 49: Update the public API baseline to declare RunIfAttribute and its
implicit public constructor in
src/ModularPipelines/Attributes/RunConditionAttribute.cs:49-49, and declare OnCI
and its implicit public constructor in
src/ModularPipelines/Conditions/OnCI.cs:23-23, resolving the Public API analyzer
findings without changing their implementations.

Apply the same fix in `@src/ModularPipelines/Attributes/RunIfAttribute.cs` around
lines 19 - 30: Covers the OnLocal type and constructor.

---

Outside diff comments:
In `@src/ModularPipelines/Attributes/OperatingSystemConditions.cs`:
- Line 186: Update GetSupportedOperatingSystems(CustomAttributeData) to resolve
each generic argument via GetSupportedOperatingSystems(Type), preserving union
semantics for grouped conditions such as OnUnix and OnWindows so
HasImpossibleCombination(Type) detects impossible combinations. Add a regression
test covering the grouped Unix/Windows conditions during category discovery.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c97a83a6-76d6-46a5-a7e0-4ed5cfe71fff

📥 Commits

Reviewing files that changed from the base of the PR and between 26af9b1 and aae6235.

📒 Files selected for processing (41)
  • docs/docs/distributed/capabilities.md
  • docs/docs/how-to/run-conditions.md
  • docs/docs/how-to/skipping.md
  • docs/docs/migrating-to-v3.md
  • src/ModularPipelines.Build/Modules/BuildSolutionOnPlatformModule.cs
  • src/ModularPipelines.Build/Modules/BuildSolutionsModule.cs
  • src/ModularPipelines.Build/Modules/CreateReleaseModule.cs
  • src/ModularPipelines.Build/Modules/FormatMarkdownModule.cs
  • src/ModularPipelines.Build/Modules/PackProjectsModule.cs
  • src/ModularPipelines.Build/Modules/PackagePathsParserModule.cs
  • src/ModularPipelines.Build/Modules/PushVersionTagModule.cs
  • src/ModularPipelines.Build/Modules/UnitTests/RunUnitTestModule.cs
  • src/ModularPipelines.Build/Modules/UploadPackagesToNugetModule.cs
  • src/ModularPipelines.GitHub/PipelineWriters/GitHubPipelineFileWriterOptions.cs
  • src/ModularPipelines/Attributes/EnvironmentVariableConditionAttributes.cs
  • src/ModularPipelines/Attributes/OperatingSystemConditionAttributes.cs
  • src/ModularPipelines/Attributes/OperatingSystemConditions.cs
  • src/ModularPipelines/Attributes/RunConditionAttribute.cs
  • src/ModularPipelines/Attributes/RunIfAllAttribute.cs
  • src/ModularPipelines/Attributes/RunIfAnyAttribute.cs
  • src/ModularPipelines/Attributes/RunIfAttribute.cs
  • src/ModularPipelines/Conditions/ConditionGroup.cs
  • src/ModularPipelines/Conditions/OnCI.cs
  • src/ModularPipelines/Conditions/OnLocal.cs
  • src/ModularPipelines/Conditions/OnUnix.cs
  • src/ModularPipelines/Conditions/OnWindows.cs
  • src/ModularPipelines/Engine/ModuleConditionHandler.cs
  • src/ModularPipelines/OperatingSystemIdentifier.cs
  • test/ModularPipelines.Distributed.UnitTests/Master/DistributedModuleExecutorTests.cs
  • test/ModularPipelines.GitHub.UnitTests/Engine/DistributedPipelineWriterTests.cs
  • test/ModularPipelines.GitHub.UnitTests/Execution/SkipDependabotAttributeTests.cs
  • test/ModularPipelines.UnitTests/Api/RunConditionApiSurfaceTests.cs
  • test/ModularPipelines.UnitTests/Attributes/OperatingSystemConditionsTests.cs
  • test/ModularPipelines.UnitTests/Attributes/ParameterizedRunConditionAttributeTests.cs
  • test/ModularPipelines.UnitTests/CommandLine/PipelineCommandLineTests.cs
  • test/ModularPipelines.UnitTests/Engine/DependencyGraphExporterTests.cs
  • test/ModularPipelines.UnitTests/Engine/IgnoredModuleResultRegistrarTests.cs
  • test/ModularPipelines.UnitTests/Engine/ModuleConditionHandlerTests.cs
  • test/ModularPipelines.UnitTests/Execution/ModuleHistoryTests.cs
  • test/ModularPipelines.UnitTests/Execution/NewRunConditionAttributeTests.cs
  • test/ModularPipelines.UnitTests/Validation/ValidationTests.cs
💤 Files with no reviewable changes (5)
  • src/ModularPipelines/Attributes/RunIfAllAttribute.cs
  • src/ModularPipelines/OperatingSystemIdentifier.cs
  • src/ModularPipelines/Attributes/RunIfAnyAttribute.cs
  • src/ModularPipelines.GitHub/PipelineWriters/GitHubPipelineFileWriterOptions.cs
  • src/ModularPipelines/Attributes/OperatingSystemConditionAttributes.cs

Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review.

Comment thread docs/docs/how-to/run-conditions.md
Comment thread docs/docs/how-to/skipping.md Outdated
Comment thread src/ModularPipelines/Attributes/RunConditionAttribute.cs
@thomhurst

Copy link
Copy Markdown
Owner Author

Fixed the CI-wide failure in dde5e9b. The run-condition removals are now recorded in PublicAPI.Unshipped.txt and the v4 replacements are declared. A CI-conditioned core build now passes with RS0016/RS0017 enforced; all 61 package baseline pairs and the baseline harness also pass.

@thomhurst

Copy link
Copy Markdown
Owner Author

Fixed the remaining CI failure by recording the removed GitHubPipelineFileWriterOptions.RunnerOperatingSystem accessors in the GitHub package PublicAPI baseline. Targeted ModularPipelines.GitHub.slnx Release build passes (3 warnings, 0 errors); all 61 PublicAPI baseline pairs and the assertion harness pass.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: Simplify run condition APIs (#4269)

Re-checked against the current head (b8bab8d), which adds two commits since the last claude[bot] review (aae6235): "fix(api): record run-condition changes" and "fix(api): record removed runner OS". Both are PublicAPI baseline (PublicAPI.Shipped.txt/PublicAPI.Unshipped.txt) entries only — no logic changed since the prior review, so the previously flagged blocking issue is still live.

Outstanding issue (unaddressed, confirmed against current code — same as previous review):

OperatingSystemConditions.HasImpossibleCombination(Type moduleType) (src/ModularPipelines/Attributes/OperatingSystemConditions.cs#L79-L88) still filters attributes with typeof(RunIfAttribute).IsAssignableFrom(type) || typeof(RunIfAllAttribute).IsAssignableFrom(type)RunIfAnyAttribute is never matched, so its OS constraint is excluded from the intersection used to detect impossible combinations.

Meanwhile DistributedWorkPublisher.CreateAssignment (src/ModularPipelines/Distributed/Master/DistributedWorkPublisher.cs#L37-L42) still iterates all IConditionAttributes unfiltered, unioning in every OperatingSystemConditions.GetTargets(...) capability, including from RunIfAny.

Net effect, unchanged from the previous review: a module decorated with both [RunIfAny<OnLinux, OnMacOS>] and [RunIf<OnWindows>] (ANDed at the module level, both attributes independently allow AllowMultiple = true) is not flagged as impossible by HasImpossibleCombination, but the published distributed assignment ends up requiring operating-system:linux|macos and windows simultaneously. CapabilityMatcher.CanExecute requires a worker to satisfy all required capabilities, and GetWorkerCapabilities derives a worker's capability set from a single OS, so no worker can ever satisfy both — the assignment becomes permanently unclaimable instead of the module being cleanly skipped. I also checked test/ModularPipelines.UnitTests/Attributes/OperatingSystemConditionsTests.cs — no test exercises HasImpossibleCombination with a RunIfAny OS constraint, so this gap has no regression coverage either.

Suggested fix (unchanged from prior review): extend HasImpossibleCombination(Type)'s attribute filter to also include RunIfAnyAttribute, unioning its alternatives before intersecting with the other (AND) constraints — mirroring what the instance-based GetSupportedOperatingSystems(IConditionAttribute) overload already does.

Also still outstanding (lower severity, P2, unchanged from prior review):

  • "Provide a FreeBSD replacement before removing OS attributes" — OperatingSystemConditions.GetOperatingSystem(Type) (src/ModularPipelines/Attributes/OperatingSystemConditions.cs#L262-L275) only maps OnWindows/OnLinux/OnMacOS; the FreeBSD capability constant and OsCapabilityDetector FreeBSD detection still exist with no OnFreeBSD condition type to target it via RunIf<T>.
  • CodeRabbit's still-unresolved finding on the metadata-only path: GetSupportedOperatingSystems(CustomAttributeData) (src/ModularPipelines/Attributes/OperatingSystemConditions.cs#L186-L207) only resolves direct OS condition types and returns null for a ConditionGroup (e.g. OnUnix), unlike its Type-based sibling which recurses into groups. So HasImpossibleCombination(Type) still can't detect an impossible [RunIf<OnUnix>] + [RunIf<OnWindows>] combination via the metadata-discovery path.

Everything else (the RunIf<T>/RunIfAll/RunIfAny API surface, the OnCI/OnLocal rename, removal of the duplicate OS attributes/enum/helper, distributed deferral of Any-logic OS conditions, migrated build modules, tests, and docs) was reviewed in prior rounds on this PR and remains correct — no new concerns found there, and the two PublicAPI-baseline-only commits since the last review are exactly what they claim to be.

@thomhurst
thomhurst force-pushed the issue-4224-run-conditions branch from b8bab8d to 6edd27f Compare August 29, 2026 01:23
@thomhurst

Copy link
Copy Markdown
Owner Author

Rebased onto current main after #4281. Resolved the public API overlap by retaining current hashing/PowerShell declarations and applying only the run-condition delta (32 removals, 14 additions). Validation: CI-conditioned core API build succeeded (6 advisory warnings, 0 errors); ModularPipelines.Tests.slnf Release build succeeded (178 existing warnings, 0 errors); 46 focused run-condition tests passed; 61 API baseline pairs passed; git diff --check passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6edd27ff95

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ModularPipelines/Attributes/OperatingSystemConditions.cs
Add the natural singular RunIf API and remove redundant or inconsistently named v4 condition APIs.
Record removed condition APIs and declare their v4 replacements so the CI PublicApiAnalyzer gate passes.
@thomhurst
thomhurst force-pushed the issue-4224-run-conditions branch from 6edd27f to 028c759 Compare August 29, 2026 02:14
@thomhurst

Copy link
Copy Markdown
Owner Author

@claude please review current head 028c759. RunIfAny/grouped OS contradiction and routing gaps are fixed, OnFreeBSD restores removed API parity, docs/API baselines are updated, and focused core/distributed tests pass.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 028c7590a3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +683 to +686
if (alternatives.Any(attribute =>
ShouldDeferOperatingSystemCondition(attribute, isDistributedMaster)))
{
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve routing for mixed grouped alternatives

When a group mixes an OS alternative with a non-platform alternative—for example, Linux OR a branch condition—this defers the entire group merely because one member has an OS target. OperatingSystemConditions.GetTargets(alternatives) returns no capability for such mixed groups, so any worker can dequeue the assignment; if a Windows worker claims it while the branch condition is false, that worker publishes a skipped result even though a Linux worker could run the module. Evaluate the non-platform alternatives on the master and retain the OS constraint when they fail rather than publishing an unrestricted assignment.

Useful? React with 👍 / 👎.

Comment on lines +114 to +116
? attribute.AttributeType.GetGenericTypeDefinition()
: attribute.AttributeType))
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Group metadata by the declared condition group

When two different IGroupedConditionAttribute classes share one ConditionGroupType and target different platforms, this metadata path groups them by their attribute types instead. It consequently intersects the alternatives as separate requirements, causing HasImpossibleCombination(Type) to mark the module impossible and skip it on a distributed master, while runtime evaluation and assignment creation correctly treat the same attributes as one OR group. Derive the grouping key from ConditionGroupType, as the instance-based path does.

Useful? React with 👍 / 👎.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: Simplify run condition APIs (#4269)

Re-reviewed against the current head (028c7590), which adds one commit since the last claude[bot] review (b8bab8d): "fix(conditions): route OS alternatives".

Previously flagged blocking issue — now fixed:

  • HasImpossibleCombination(Type)'s attribute filter now includes RunIfAnyAttribute (src/ModularPipelines/Attributes/OperatingSystemConditions.cs:98-100), and grouped RunIfAny-style alternatives are unioned via a new GetSupportedOperatingSystemsForAlternatives helper before being intersected with the AND-logic constraints (lines 110-120). This closes the "module unclaimable on any distributed worker" gap from the prior review. Also confirmed: DistributedWorkPublisher and ModuleConditionHandler both now correctly defer/route grouped Any OS conditions, backed by new tests.

New issue introduced by this commit (blocking):

OperatingSystemConditions.HasImpossibleCombination(Type moduleType) (src/ModularPipelines/Attributes/OperatingSystemConditions.cs:110-115) groups IGroupedConditionAttribute metadata by CLR type instead of by the semantic ConditionGroupType:

.GroupBy(static attribute => attribute.AttributeType.IsGenericType
    ? attribute.AttributeType.GetGenericTypeDefinition()
    : attribute.AttributeType)

This diverges from its own sibling overload two methods above it (HasImpossibleCombination(IEnumerable<IConditionAttribute>), line 79), which correctly groups by attribute.ConditionGroupType — the actual contract IGroupedConditionAttribute defines for "these should be OR'd together." The codebase already relies on cross-class ConditionGroupType sharing as a supported idiom: RunIfBranchAttribute and RunIfBranchStartsWithAttribute (src/ModularPipelines.Git/Attributes/) are two distinct, non-generic classes that both return typeof(BranchConditionHelper), and BranchConditionLoggingTests explicitly asserts their ConditionGroupTypes are equal so they get OR'd as one alternative group.

Because the metadata-only path can't call an instance property on CustomAttributeData, it approximates grouping by type instead — but AttributeType (or its generic definition) is not equivalent to ConditionGroupType for cross-class groups, and nothing in IGroupedConditionAttribute ties the two together. Today this happens to be harmless only because the two shipped IGroupedConditionAttribute implementers (the branch attributes) are non-generic, so GetSupportedOperatingSystems(CustomAttributeData) returns null for them immediately (zero generic arguments) and IntersectConstraint no-ops on null — but that's incidental, not by design. Any future or third-party grouped OS attribute that mirrors the branch-attribute pattern (distinct generic classes sharing one ConditionGroupType to form an OS alternative) would be split into separate single-alternative groups here and incorrectly intersected instead of unioned, causing HasImpossibleCombination to report a false "mutually exclusive operating systems" and permanently skip a valid module on the distributed master — even though the real per-instance evaluation path would run it fine.

Suggested fix: resolve the real ConditionGroupType for the metadata-only path too, e.g. via the CustomAttributeMetadata.Create<T> helper already used elsewhere in this file to construct a live instance and read .ConditionGroupType, rather than approximating it from the CLR type. That keeps both HasImpossibleCombination overloads using the same grouping key the interface actually defines.

Lower severity, non-blocking:

  • OnUnix (src/ModularPipelines/Conditions/OnUnix.cs:22) still only unions OnLinux and OnMacOS. This PR promotes OnFreeBSD to a first-class platform condition, and the docs (run-conditions.md) now list OnFreeBSD and OnUnix side by side as built-ins — a user targeting "any Unix-like OS" via [RunIf<OnUnix>] would reasonably expect FreeBSD to match. Worth a conscious call either way (extend the group, or note the exclusion in the XML doc) rather than a silent gap.
  • GetSupportedOperatingSystemsForAlternatives (lines 238-254 and 256-272) is duplicated verbatim across the IConditionAttribute and CustomAttributeData overloads, differing only in which per-element resolver they call. Given the bug above already stems from these two parallel code paths drifting apart, collapsing the shared union/short-circuit logic into one generic helper (or at least keeping them adjacent with a comment noting they must stay in sync) would reduce the chance of a repeat.

Everything else (the RunIf<T>/RunIfAll/RunIfAny API surface, OnCI/OnLocal rename, removal of the duplicate OS attributes/enum/helper, migrated build modules, tests, and docs) was reviewed in prior rounds and remains correct.

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.

v4: add RunIf<T>; IsCI/IsLocalOnCI/OnLocal; remove the RunIfOperatingSystem/SkipIfOperatingSystem duplicates

1 participant