From 637b7de18ab909103d4f53075409938300c0cb1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 23:34:39 +0000 Subject: [PATCH 1/5] Initial plan From 2a8d337e2bb525a7a114966fb8f5f0444f96e56a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 23:45:10 +0000 Subject: [PATCH 2/5] Add copy constructors to TaskOptions and sub-classes Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com> --- src/Abstractions/TaskOptions.cs | 82 +++++++++++++++--- test/Abstractions.Tests/TaskOptionsTests.cs | 94 +++++++++++++++++++++ 2 files changed, 166 insertions(+), 10 deletions(-) diff --git a/src/Abstractions/TaskOptions.cs b/src/Abstractions/TaskOptions.cs index c38144b6..cd227dab 100644 --- a/src/Abstractions/TaskOptions.cs +++ b/src/Abstractions/TaskOptions.cs @@ -30,6 +30,17 @@ public TaskOptions(TaskRetryOptions? retry = null, IDictionary? this.Tags = tags; } + /// + /// Initializes a new instance of the class by copying from another instance. + /// + /// The task options to copy from. + public TaskOptions(TaskOptions options) + { + Check.NotNull(options); + this.Retry = options.Retry; + this.Tags = options.Tags; + } + /// /// Gets the task retry options. /// @@ -96,12 +107,29 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) : base(options) { this.InstanceId = instanceId; - if (instanceId is null && options is SubOrchestrationOptions derived) + if (options is SubOrchestrationOptions derived) { - this.InstanceId = derived.InstanceId; + if (instanceId is null) + { + this.InstanceId = derived.InstanceId; + } + + this.Version = derived.Version; } } + /// + /// Initializes a new instance of the class by copying from another instance. + /// + /// The sub-orchestration options to copy from. + public SubOrchestrationOptions(SubOrchestrationOptions options) + : base(options) + { + Check.NotNull(options); + this.InstanceId = options.InstanceId; + this.Version = options.Version; + } + /// /// Gets the orchestration instance ID. /// @@ -116,15 +144,49 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) /// /// Options for submitting new orchestrations via the client. /// -/// -/// The unique ID of the orchestration instance to schedule. If not specified, a new GUID value is used. -/// -/// -/// The time when the orchestration instance should start executing. If not specified or if a date-time in the past -/// is specified, the orchestration instance will be scheduled immediately. -/// -public record StartOrchestrationOptions(string? InstanceId = null, DateTimeOffset? StartAt = null) +public record StartOrchestrationOptions { + /// + /// Initializes a new instance of the class. + /// + /// + /// The unique ID of the orchestration instance to schedule. If not specified, a new GUID value is used. + /// + /// + /// The time when the orchestration instance should start executing. If not specified or if a date-time in the past + /// is specified, the orchestration instance will be scheduled immediately. + /// + public StartOrchestrationOptions(string? instanceId = null, DateTimeOffset? startAt = null) + { + this.InstanceId = instanceId; + this.StartAt = startAt; + } + + /// + /// Initializes a new instance of the class by copying from another instance. + /// + /// The start orchestration options to copy from. + public StartOrchestrationOptions(StartOrchestrationOptions options) + { + Check.NotNull(options); + this.InstanceId = options.InstanceId; + this.StartAt = options.StartAt; + this.Tags = options.Tags; + this.Version = options.Version; + this.DedupeStatuses = options.DedupeStatuses; + } + + /// + /// Gets the unique ID of the orchestration instance to schedule. If not specified, a new GUID value is used. + /// + public string? InstanceId { get; init; } + + /// + /// Gets the time when the orchestration instance should start executing. If not specified or if a date-time in the past + /// is specified, the orchestration instance will be scheduled immediately. + /// + public DateTimeOffset? StartAt { get; init; } + /// /// Gets the tags to associate with the orchestration instance. /// diff --git a/test/Abstractions.Tests/TaskOptionsTests.cs b/test/Abstractions.Tests/TaskOptionsTests.cs index 3e805a9e..1576a91b 100644 --- a/test/Abstractions.Tests/TaskOptionsTests.cs +++ b/test/Abstractions.Tests/TaskOptionsTests.cs @@ -148,4 +148,98 @@ public void WithDedupeStatuses_ConvertsAllEnumValuesToStrings() result.DedupeStatuses.Should().Contain(status.ToString()); } } + + [Fact] + public void TaskOptions_CopyConstructor_CopiesAllProperties() + { + // Arrange + RetryPolicy policy = new(3, TimeSpan.FromSeconds(1)); + TaskRetryOptions retry = new(policy); + Dictionary tags = new() { { "key1", "value1" }, { "key2", "value2" } }; + TaskOptions original = new(retry, tags); + + // Act + TaskOptions copy = new(original); + + // Assert + copy.Retry.Should().Be(original.Retry); + copy.Tags.Should().BeSameAs(original.Tags); + } + + [Fact] + public void SubOrchestrationOptions_CopyConstructor_CopiesAllProperties() + { + // Arrange + RetryPolicy policy = new(3, TimeSpan.FromSeconds(1)); + TaskRetryOptions retry = new(policy); + Dictionary tags = new() { { "key1", "value1" }, { "key2", "value2" } }; + string instanceId = Guid.NewGuid().ToString(); + TaskVersion version = new("1.0"); + SubOrchestrationOptions original = new(retry, instanceId) + { + Tags = tags, + Version = version, + }; + + // Act + SubOrchestrationOptions copy = new(original); + + // Assert + copy.Retry.Should().Be(original.Retry); + copy.Tags.Should().BeSameAs(original.Tags); + copy.InstanceId.Should().Be(original.InstanceId); + copy.Version.Should().Be(original.Version); + } + + [Fact] + public void SubOrchestrationOptions_CopyFromTaskOptions_CopiesVersionWhenSourceIsSubOrchestration() + { + // Arrange + RetryPolicy policy = new(3, TimeSpan.FromSeconds(1)); + TaskRetryOptions retry = new(policy); + Dictionary tags = new() { { "key1", "value1" } }; + string instanceId = Guid.NewGuid().ToString(); + TaskVersion version = new("1.0"); + SubOrchestrationOptions original = new(retry, instanceId) + { + Tags = tags, + Version = version, + }; + + // Act + SubOrchestrationOptions copy = new(original as TaskOptions); + + // Assert + copy.Retry.Should().Be(original.Retry); + copy.Tags.Should().BeSameAs(original.Tags); + copy.InstanceId.Should().Be(original.InstanceId); + copy.Version.Should().Be(original.Version); + } + + [Fact] + public void StartOrchestrationOptions_CopyConstructor_CopiesAllProperties() + { + // Arrange + string instanceId = Guid.NewGuid().ToString(); + DateTimeOffset startAt = DateTimeOffset.UtcNow.AddHours(1); + Dictionary tags = new() { { "key1", "value1" }, { "key2", "value2" } }; + TaskVersion version = new("1.0"); + List dedupeStatuses = new() { "Completed", "Failed" }; + StartOrchestrationOptions original = new(instanceId, startAt) + { + Tags = tags, + Version = version, + DedupeStatuses = dedupeStatuses, + }; + + // Act + StartOrchestrationOptions copy = new(original); + + // Assert + copy.InstanceId.Should().Be(original.InstanceId); + copy.StartAt.Should().Be(original.StartAt); + copy.Tags.Should().BeSameAs(original.Tags); + copy.Version.Should().Be(original.Version); + copy.DedupeStatuses.Should().BeSameAs(original.DedupeStatuses); + } } From 2fd545ac364128dc54a370c9048e115491079838 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 23:52:10 +0000 Subject: [PATCH 3/5] Remove redundant null check in SubOrchestrationOptions copy constructor Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com> --- src/Abstractions/TaskOptions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Abstractions/TaskOptions.cs b/src/Abstractions/TaskOptions.cs index cd227dab..4b48c02e 100644 --- a/src/Abstractions/TaskOptions.cs +++ b/src/Abstractions/TaskOptions.cs @@ -125,7 +125,6 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) public SubOrchestrationOptions(SubOrchestrationOptions options) : base(options) { - Check.NotNull(options); this.InstanceId = options.InstanceId; this.Version = options.Version; } From 74751af64d04dadfdb04f5c59e7f8bc554adccc4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:52:37 +0000 Subject: [PATCH 4/5] Address review feedback: add null check and preserve PascalCase parameters Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com> --- TestBackwardCompat.csproj | 9 +++++++++ src/Abstractions/TaskOptions.cs | 13 ++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 TestBackwardCompat.csproj diff --git a/TestBackwardCompat.csproj b/TestBackwardCompat.csproj new file mode 100644 index 00000000..16ee0194 --- /dev/null +++ b/TestBackwardCompat.csproj @@ -0,0 +1,9 @@ + + + Exe + net10.0 + + + + + diff --git a/src/Abstractions/TaskOptions.cs b/src/Abstractions/TaskOptions.cs index 4b48c02e..7c0d54ee 100644 --- a/src/Abstractions/TaskOptions.cs +++ b/src/Abstractions/TaskOptions.cs @@ -125,6 +125,7 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) public SubOrchestrationOptions(SubOrchestrationOptions options) : base(options) { + Check.NotNull(options); this.InstanceId = options.InstanceId; this.Version = options.Version; } @@ -148,17 +149,19 @@ public record StartOrchestrationOptions /// /// Initializes a new instance of the class. /// - /// + /// /// The unique ID of the orchestration instance to schedule. If not specified, a new GUID value is used. /// - /// + /// /// The time when the orchestration instance should start executing. If not specified or if a date-time in the past /// is specified, the orchestration instance will be scheduled immediately. /// - public StartOrchestrationOptions(string? instanceId = null, DateTimeOffset? startAt = null) +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter - using PascalCase to maintain backward compatibility with positional record syntax + public StartOrchestrationOptions(string? InstanceId = null, DateTimeOffset? StartAt = null) +#pragma warning restore SA1313 { - this.InstanceId = instanceId; - this.StartAt = startAt; + this.InstanceId = InstanceId; + this.StartAt = StartAt; } /// From 50a108518173f4b9b3717eb3a87bb55aa6697776 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 21 Dec 2025 04:52:59 +0000 Subject: [PATCH 5/5] Remove accidentally committed test file Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com> --- TestBackwardCompat.csproj | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 TestBackwardCompat.csproj diff --git a/TestBackwardCompat.csproj b/TestBackwardCompat.csproj deleted file mode 100644 index 16ee0194..00000000 --- a/TestBackwardCompat.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - net10.0 - - - - -