Skip to content

Releases: ProcedureKit/ProcedureKit

5.2.0

03 Apr 17:28
a7fa565
Compare
Choose a tag to compare

5.2.0

Xcode 10.2 & Swift 5 compatible.

5.1.0

27 Mar 13:39
06918bc
Compare
Choose a tag to compare

5.1.0

This will be the last update specifically supporting Xcode 10.1 and Swift 4.2.

New Procedures

  1. [919]: JSON Coding procedures.

    This changes introduced a generic JSONDecodingProcedure and JSONEncodingProcedure which can be used to decode/decode a Data representing a UTF-8 encoded JSON string into a suitable Codable type. The procedure allows full injection of the JSONDecoder with a convenience initializer to user or override the default behavior. Additionally, the Data can be inject from a network procedure. For decoding errors - the procedure will fail with the coding error from the JSONDecoder. This might be quite tricky to recover from and manage in production code, so in some cases it would make sense to decode into a type which can handle JSON error responses, e.g. {"message": "Failed to authorize"}.

Other Changes

  1. [908, 909]: Updates the parameter names in method signature named with: Error? to include error. This greatly improves code completion. Thanks to @pronebird and @juliensagot for these.
  2. [906]: Updates to the logging mechanisms.
  3. [918]: The Identity property of Procedure now uses ObjectIdentifier and Hasher under the hood instead of UUIDs. Thanks to
  4. [912]: Fixes some public accessor attributes for NetworkRecovery - thanks to @ericyanush for this one.
  5. [923]: Added an integration point in CI to check that SwiftPM was correctly integrating.
  6. [924]: Fixes public accessor methods to the LaunchRequest type in ProcessProcedure.

5.0.0

27 Mar 08:40
Compare
Choose a tag to compare

5.0.0

This is a rather long-awaited next major version of ProcedureKit.

Headline Changes

  1. Networking procedures no longer use an associated type for the URLSession. Instead Session is a free-floating protocol. This makes general usage, subclassing and composing much simpler.
  2. There is now a Core Data module
  3. BlockProcedure API has changed.
  4. Procedure only supports a single Error value, instead of [Error] - this has had some fairly wide reaching changes to APIs.
  5. New built-in logger, which uses os_log by default.
  6. Changes to UIProcedure in ProcedureKitMobile module.

Breaking Changes

  1. [823]: Removes associated types from Network

    Originally raised as an issue by @ericyanush in which I totally missed the point initially. But, after thinking about it more, made so much sense. Instead of having a generic URLSessionTaskFactory protocol, where the various types of tasks were associated types, we now just have a non-generic NetworkSession protocol, to which URLSession conforms. The impact of this subtle change, is that what was once: NetworkDataProcedure<Session: URLSessionTaskFactory> is now NetworkDataProcedure. In otherwords, no longer generic, and now super easy to use as that generic Session doesn't leak all over the place.

  2. [#875]: Refactored BlockProcedure

    There has been a long-standing wish for BlockProcedure instances to "receive themselves" in their block to allow for access to its logger etc. In v5, the following is all possible, see this comment:

    1. Simple synchronous block (existing functionality):

      let block = BlockProcedure { 
          print("Hello World")
      }
    2. Synchonous block, accessing the procedure inside the block:

      let block = BlockProcedure { this in
          this.log.debug.message("Hello World")
          this.finish()
      }

      Note that here, the block is responsible for finishing itself - i.e. call .finish() or .finish(with:) to finish the Procedure. Using this initializer, by default, BlockProcedure will add a TimeoutObserver to itself, using defaultTimeoutInterval which is set to 3 seconds. This can be modified if needed.

      BlockProcedure.defaultTimeoutInterval = 5
    3. Asynchronous block with cancellation check, AsyncBlockProcedure and CancellableBlockProcedure get deprecated warnings.

      let block = BlockProcedure { this in
          guard !this.isCancelled else { this.finish() }
          DispatchQueue.default.async {
             print("Hello world")
             this.finish()
          }
      }
    4. ResultProcedure as been re-written as a subclass of BlockProcedure (previously, it was the superclass). Existing functionality has been maintained:

      let hello = ResultProcedure { "Hello World" }
  3. [#851]: Errors

    At WWDC18 I spent some time with some Swift engineers from Apple talking about framework design and error handling. The key take-away from these discussions was to increase clarity which reduces confusion, and makes intent clear.

    This theme drove some significant changes. To increase clarity, each Procedure can only have a single Error, because ultimately, how can a framework consumer "handle" an array of Error values over just a single one? I realised that the only reason Procedure has an [Error] property at all was from GroupProcedure collecting all of the errors from its children, yet the impact of this is felt throughout the codebase.

    This means, to finish a procedure with an error, use:

    finish(with: .downloadFailedError) // this is a made up error type

    Observers only receive a single error now:

    procedure.addDidFinishBlockObserver { (this, error) in
        guard let error = error else {
            // there is an error, the block argument is Error? type
        return
        }
    
    // etc
    }

    Plus more API changes in Procedure and GroupProcedure which will result in deprecation warnings for framework consumers.

    For GroupProcedure itself, it will now only set its own error to the first error received. However, to access the errors from child procedures, use the .children property. Something like:

    let errors = group.children.operationsAndProcedures.1.compactMap { $0.error }
  4. [#861, #870]: Logger

    ProcedureKit has its own logging system, which has received an overhawl in v5. The changes are:

     1. Now uses `os_log` instead of `print()` where available.
    
    1. Dedicated severity levels for caveman debugging & user event. See this comment.
    2. Slight API change:
      procedure.log.info.message("This is my debug message")
      previously, it was:
      procedure.log.info("This is my debug message")
      For module-wide settings:
      Log.enabled = true
      Log.severity = .debug // default is .warning
      Log.writer = CustomLogWriter() // See LogWriter protocol
      Log.formatter = CustomLogFormatter() // See LogFormatter protocol
  5. [#860]: Swift 3/4 API naming & conventions

    @lukeredpath initially raised the issue in #796, that some APIs such as add(condition: aCondition) did not Swift 3/4 API guidelines, and contributed to inconsistency within the framework. These have now been tidied up.

New Features & Improvements

  1. [#830, #837]: Swift 4.1 & Xcode 9.3 support, (Xcode 10 is ready to go).

    These changes take advantage of Swift 4.1 capabilities, such as synthesized Equatable and conditional conformance.

  2. [#828, #833]: Result Injection & Binding

    Result Injection conformance is added to RepeatProcedure (and subclasses such as RetryProcedure & NetworkProcedure). This means the input can be set on the out RepeatProcedure, and this value will be set on every instance of the target procedure (assuming it also conforms to InputProcedure). This avoids having to jump through hoops like this.

    Additionally, a new binding API can be used, particularly with GroupProcedure subclasses, so that the input of a child procedure is "bound" to that of the group itself, likewise, the output of the group is bound to a child. This makes it very easy to encapsulate a chain of procedures which use result injection into a GroupProcedure subclass. See the docs.

  3. [#834]: Adds BatchProcedure

    BatchProcedure is a GroupProcedure subclass which can be used to batch process a homogeneous array of objects, so that we get [T] -> [V] via a procedure which does T -> V. We already have MapProcedure which does this via a closure, and so is synchronous, and useful for simple data transforms. BatchProcedure allows asynchronous processing via a custom procedure. This is actually a pretty common situation in production apps. For example, consider an API response for a gallery of images, we can use BatchProcedure to get all the images in the gallery.

  4. [#838]: Adds IgnoreErrorsProcedure

    IgnoreErrorsProcedure will safely wrap another procedure to execute it and suppress any errors. This can be useful for fire, forget and ignore type behavior.

  5. [#843, #844, #847, #849]: Adds ProcedureKitCoreData.

    • LoadCoreDataProcedure - intended to be subclassed by framework consumers for their project, see the docs.
    • MakeFetchedResultControllerProcedure
    • SaveManagedObjectContext
    • InsertManagedObjectsProcedure
    • MakesBackgroundManagedObjectContext - a protocol to allow mixed usage of NSPersistentContainer, NSManagedObjectContext and NSPersistentStoreCoordinator.
  6. [#840, #858, #868]: Adds UIBlockProcedure

    UIBlockProcedure replaces UIProcedure, and it essentially is a block which will always run on the main queue. It is the basis for other UI procedures.

  7. [#841, #873, [#874](https://github.com/ProcedureKit/ProcedureKit...

Read more

5.0.0 Beta 2

26 Sep 08:18
bd716cd
Compare
Choose a tag to compare
5.0.0 Beta 2 Pre-release
Pre-release

5.0.0

This is a rather long-awaited next major version of ProcedureKit. It is ready for Xcode 10 and Swift 4.2.

Headline Changes

  1. Networking procedures no longer use an associated type for the URLSession. Instead Session is a free-floating protocol. This makes general usage, subclassing and composing much simpler.
  2. There is now a Core Data module
  3. BlockProcedure API has changed.
  4. Procedure only supports a single Error value, instead of [Error] - this has had some fairly wide reaching changes to APIs.
  5. New built-in logger, which uses os_log by default.
  6. Changes to UIProcedure in ProcedureKitMobile module.

Breaking Changes

  1. [823]: Removes associated types from Network

    Originally raised as an issue by @ericyanush in which I totally missed the point initially. But, after thinking about it more, made so much sense. Instead of having a generic URLSessionTaskFactory protocol, where the various types of tasks were associated types, we now just have a non-generic NetworkSession protocol, to which URLSession conforms. The impact of this subtle change, is that what was once: NetworkDataProcedure<Session: URLSessionTaskFactory> is now NetworkDataProcedure. In otherwords, no longer generic, and now super easy to use as that generic Session doesn't leak all over the place.

  2. [#875]: Refactored BlockProcedure

    There has been a long-standing wish for BlockProcedure instances to "receive themselves" in their block to allow for access to its logger etc. In v5, the following is all possible, see this comment:

    1. Simple synchronous block (existing functionality):

      let block = BlockProcedure { 
          print("Hello World")
      }
    2. Synchonous block, accessing the procedure inside the block:

      let block = BlockProcedure { this in
          this.log.debug.message("Hello World")
          this.finish()
      }

      Note that here, the block is responsible for finishing itself - i.e. call .finish() or .finish(with:) to finish the Procedure. Using this initializer, by default, BlockProcedure will add a TimeoutObserver to itself, using defaultTimeoutInterval which is set to 3 seconds. This can be modified if needed.

      BlockProcedure.defaultTimeoutInterval = 5
    3. Asynchronous block with cancellation check, AsyncBlockProcedure and CancellableBlockProcedure get deprecated warnings.

      let block = BlockProcedure { this in
          guard !this.isCancelled else { this.finish() }
          DispatchQueue.default.async {
             print("Hello world")
             this.finish()
          }
      }
    4. ResultProcedure as been re-written as a subclass of BlockProcedure (previously, it was the superclass). Existing functionality has been maintained:

      let hello = ResultProcedure { "Hello World" }
  3. [#851]: Errors

    At WWDC18 I spent some time with some Swift engineers from Apple talking about framework design and error handling. The key take-away from these discussions was to increase clarity which reduces confusion, and makes intent clear.

    This theme drove some significant changes. To increase clarity, each Procedure can only have a single Error, because ultimately, how can a framework consumer "handle" an array of Error values over just a single one? I realised that the only reason Procedure has an [Error] property at all was from GroupProcedure collecting all of the errors from its children, yet the impact of this is felt throughout the codebase.

    This means, to finish a procedure with an error, use:

    finish(with: .downloadFailedError) // this is a made up error type

    Observers only receive a single error now:

    procedure.addDidFinishBlockObserver { (this, error) in
        guard let error = error else {
            // there is an error, the block argument is Error? type
        return
        }
    
    // etc
    }

    Plus more API changes in Procedure and GroupProcedure which will result in deprecation warnings for framework consumers.

    For GroupProcedure itself, it will now only set its own error to the first error received. However, to access the errors from child procedures, use the .children property. Something like:

    let errors = group.children.operationsAndProcedures.1.compactMap { $0.error }
  4. [#861, #870]: Logger

    ProcedureKit has its own logging system, which has received an overhawl in v5. The changes are:

     1. Now uses `os_log` instead of `print()` where available.
    
    1. Dedicated severity levels for caveman debugging & user event. See this comment.
    2. Slight API change:
      procedure.log.info.message("This is my debug message")
      previously, it was:
      procedure.log.info("This is my debug message")
      For module-wide settings:
      Log.enabled = true
      Log.severity = .debug // default is .warning
      Log.writer = CustomLogWriter() // See LogWriter protocol
      Log.formatter = CustomLogFormatter() // See LogFormatter protocol
  5. [#860]: Swift 3/4 API naming & conventions

    @lukeredpath initially raised the issue in #796, that some APIs such as add(condition: aCondition) did not Swift 3/4 API guidelines, and contributed to inconsistency within the framework. These have now been tidied up.

New Features & Improvements

  1. [#830, #837]: Swift 4.1 & Xcode 9.3 support, (Xcode 10 is ready to go).

    These changes take advantage of Swift 4.1 capabilities, such as synthesized Equatable and conditional conformance.

  2. [#828, #833]: Result Injection & Binding

    Result Injection conformance is added to RepeatProcedure (and subclasses such as RetryProcedure & NetworkProcedure). This means the input can be set on the out RepeatProcedure, and this value will be set on every instance of the target procedure (assuming it also conforms to InputProcedure). This avoids having to jump through hoops like this.

    Additionally, a new binding API can be used, particularly with GroupProcedure subclasses, so that the input of a child procedure is "bound" to that of the group itself, likewise, the output of the group is bound to a child. This makes it very easy to encapsulate a chain of procedures which use result injection into a GroupProcedure subclass. See the docs.

  3. [#834]: Adds BatchProcedure

    BatchProcedure is a GroupProcedure subclass which can be used to batch process a homogeneous array of objects, so that we get [T] -> [V] via a procedure which does T -> V. We already have MapProcedure which does this via a closure, and so is synchronous, and useful for simple data transforms. BatchProcedure allows asynchronous processing via a custom procedure. This is actually a pretty common situation in production apps. For example, consider an API response for a gallery of images, we can use BatchProcedure to get all the images in the gallery.

  4. [#838]: Adds IgnoreErrorsProcedure

    IgnoreErrorsProcedure will safely wrap another procedure to execute it and suppress any errors. This can be useful for fire, forget and ignore type behavior.

  5. [#843, #844, #847, #849]: Adds ProcedureKitCoreData.

    • LoadCoreDataProcedure - intended to be subclassed by framework consumers for their project, see the docs.
    • MakeFetchedResultControllerProcedure
    • SaveManagedObjectContext
    • InsertManagedObjectsProcedure
    • MakesBackgroundManagedObjectContext - a protocol to allow mixed usage of NSPersistentContainer, NSManagedObjectContext and NSPersistentStoreCoordinator.
  6. [#840, #858, #868]: Adds UIBlockProcedure

    UIBlockProcedure replaces UIProcedure, and it essentially is a block which will always run on the main queue. It is the basis for other UI procedures.

  7. [#841, #873, [#874](htt...

Read more

5.0.0 Beta 1

29 Aug 16:21
e0ecb77
Compare
Choose a tag to compare
5.0.0 Beta 1 Pre-release
Pre-release

5.0.0

This is a rather long-awaited next major version of ProcedureKit.

Headline Changes

  1. Networking procedures no longer use an associated type for the URLSession. Instead Session is a free-floating protocol. This makes general usage, subclassing and composing much simpler.
  2. There is now a Core Data module
  3. BlockProcedure API has changed.
  4. Procedure only supports a single Error value, instead of [Error] - this has had some fairly wide reaching changes to APIs.
  5. New built-in logger, which uses os_log by default.
  6. Changes to UIProcedure in ProcedureKitMobile module.

Breaking Changes

  1. [823]: Removes associated types from Network

    Originally raised as an issue by @ericyanush in which I totally missed the point initially. But, after thinking about it more, made so much sense. Instead of having a generic URLSessionTaskFactory protocol, where the various types of tasks were associated types, we now just have a non-generic NetworkSession protocol, to which URLSession conforms. The impact of this subtle change, is that what was once: NetworkDataProcedure<Session: URLSessionTaskFactory> is now NetworkDataProcedure. In otherwords, no longer generic, and now super easy to use as that generic Session doesn't leak all over the place.

  2. [#875]: Refactored BlockProcedure

    There has been a long-standing wish for BlockProcedure instances to "receive themselves" in their block to allow for access to its logger etc. In v5, the following is all possible, see this comment:

    1. Simple synchronous block (existing functionality):

      let block = BlockProcedure { 
          print("Hello World")
      }
    2. Synchonous block, accessing the procedure inside the block:

      let block = BlockProcedure { this in
          this.log.debug.message("Hello World")
          this.finish()
      }

      Note that here, the block is responsible for finishing itself - i.e. call .finish() or .finish(with:) to finish the Procedure. Using this initializer, by default, BlockProcedure will add a TimeoutObserver to itself, using defaultTimeoutInterval which is set to 3 seconds. This can be modified if needed.

      BlockProcedure.defaultTimeoutInterval = 5
    3. Asynchronous block with cancellation check, AsyncBlockProcedure and CancellableBlockProcedure get deprecated warnings.

      let block = BlockProcedure { this in
          guard !this.isCancelled else { this.finish() }
          DispatchQueue.default.async {
             print("Hello world")
             this.finish()
          }
      }
    4. ResultProcedure as been re-written as a subclass of BlockProcedure (previously, it was the superclass). Existing functionality has been maintained:

      let hello = ResultProcedure { "Hello World" }
  3. [#851]: Errors

    At WWDC18 I spent some time with some Swift engineers from Apple talking about framework design and error handling. The key take-away from these discussions was to increase clarity which reduces confusion, and makes intent clear.

    This theme drove some significant changes. To increase clarity, each Procedure can only have a single Error, because ultimately, how can a framework consumer "handle" an array of Error values over just a single one? I realised that the only reason Procedure has an [Error] property at all was from GroupProcedure collecting all of the errors from its children, yet the impact of this is felt throughout the codebase.

    This means, to finish a procedure with an error, use:

    finish(with: .downloadFailedError) // this is a made up error type

    Observers only receive a single error now:

    procedure.addDidFinishBlockObserver { (this, error) in
        guard let error = error else {
            // there is an error, the block argument is Error? type
        return
        }
    
    // etc
    }

    Plus more API changes in Procedure and GroupProcedure which will result in deprecation warnings for framework consumers.

    For GroupProcedure itself, it will now only set its own error to the first error received. However, to access the errors from child procedures, use the .children property. Something like:

    let errors = group.children.operationsAndProcedures.1.compactMap { $0.error }
  4. [#861, #870]: Logger

    ProcedureKit has its own logging system, which has received an overhawl in v5. The changes are:

     1. Now uses `os_log` instead of `print()` where available.
    
    1. Dedicated severity levels for caveman debugging & user event. See this comment.
    2. Slight API change:
      procedure.log.info.message("This is my debug message")
      previously, it was:
      procedure.log.info("This is my debug message")
      For module-wide settings:
      Log.enabled = true
      Log.severity = .debug // default is .warning
      Log.writer = CustomLogWriter() // See LogWriter protocol
      Log.formatter = CustomLogFormatter() // See LogFormatter protocol
  5. [#860]: Swift 3/4 API naming & conventions

    @lukeredpath initially raised the issue in #796, that some APIs such as add(condition: aCondition) did not Swift 3/4 API guidelines, and contributed to inconsistency within the framework. These have now been tidied up.

New Features & Improvements

  1. [#830, #837]: Swift 4.1 & Xcode 9.3 support, (Xcode 10 is ready to go).

    These changes take advantage of Swift 4.1 capabilities, such as synthesized Equatable and conditional conformance.

  2. [#828, #833]: Result Injection & Binding

    Result Injection conformance is added to RepeatProcedure (and subclasses such as RetryProcedure & NetworkProcedure). This means the input can be set on the out RepeatProcedure, and this value will be set on every instance of the target procedure (assuming it also conforms to InputProcedure). This avoids having to jump through hoops like this.

    Additionally, a new binding API can be used, particularly with GroupProcedure subclasses, so that the input of a child procedure is "bound" to that of the group itself, likewise, the output of the group is bound to a child. This makes it very easy to encapsulate a chain of procedures which use result injection into a GroupProcedure subclass. See the docs.

  3. [#834]: Adds BatchProcedure

    BatchProcedure is a GroupProcedure subclass which can be used to batch process a homogeneous array of objects, so that we get [T] -> [V] via a procedure which does T -> V. We already have MapProcedure which does this via a closure, and so is synchronous, and useful for simple data transforms. BatchProcedure allows asynchronous processing via a custom procedure. This is actually a pretty common situation in production apps. For example, consider an API response for a gallery of images, we can use BatchProcedure to get all the images in the gallery.

  4. [#838]: Adds IgnoreErrorsProcedure

    IgnoreErrorsProcedure will safely wrap another procedure to execute it and suppress any errors. This can be useful for fire, forget and ignore type behavior.

  5. [#843, #844, #847, #849]: Adds ProcedureKitCoreData.

    • LoadCoreDataProcedure - intended to be subclassed by framework consumers for their project, see the docs.
    • MakeFetchedResultControllerProcedure
    • SaveManagedObjectContext
    • InsertManagedObjectsProcedure
    • MakesBackgroundManagedObjectContext - a protocol to allow mixed usage of NSPersistentContainer, NSManagedObjectContext and NSPersistentStoreCoordinator.
  6. [#840, #858, #868]: Adds UIBlockProcedure

    UIBlockProcedure replaces UIProcedure, and it essentially is a block which will always run on the main queue. It is the basis for other UI procedures.

  7. [#841, #873, [#874](https://github.com/ProcedureKit/ProcedureKit...

Read more

4.5.0

13 Feb 23:13
ba53421
Compare
Choose a tag to compare

4.5.0

Swift 4.0

  1. #816 Updates for Xcode 9.2 and Swift 4.0. Thanks to @jshier for making the updates. Included here are updates to the Travis config too.

Improvements

  1. #781 Some significant performance and reliability improvements for BackgroundObserver by @swiftlyfalling.

Deprecations

  1. #818 UserIntent property on Procedure has been deprecated. Suggestion is to set the underlying queue priority.

4.4.0 (#805)

05 Oct 21:42
Compare
Choose a tag to compare

4.4.0

Breaking Change

  1. #787 Updates to a minimum version of watchOS 3. Technically, this is a breaking change, but, realistically, anyone building for  Watch will be at least on watchOS 3 now.

Others

  1. #802 Updates iOS Simulators to iOS 11 in Fastlane
  2. #801 Removes SwiftLint
  3. #795 Fixes an issue with Conditions and suspended ProcedureQueues

4.3.2 (#794)

25 Aug 11:26
Compare
Choose a tag to compare

4.3.2

  1. #790,#791 Fixes a mistake which hid the initialiser of ReverseGeocodeUserLocation which renders it un-usable 🙄. Thanks to Anatoliy for raising the issue. There really aught to be some way of having autogenerated tests for this type of bug.

  2. #793 Migrates ProcedureKit's CI to a complementary account on BuildKite. You will still need an account to view this, however, it means that open source contributors can be added to the BK account without cost. Please get in touch if you want an invite. Thanks to @keithpitt and @ticky for migrating our pipeline & history between orgs.

    In addition to this, I have setup a Mac in MacStadium, in addition to my own build server. This means that we should have effectively got constant uptime of agents to build CI.

    In light of these changes, I've disabled the Travis service, which has proved to be slow and un-reliable. The travis.yml will stay and remain working for anyone who maintains their own fork.

4.3.1 (#786)

13 Aug 14:00
Compare
Choose a tag to compare

4.3.1

  1. #785 To get round an error with Xcode 9 betas archiving applications.

4.3.0 (#780)

03 Aug 18:59
Compare
Choose a tag to compare

4.3.0

Documentation

  1. #750, #762, #763, #751, #766, #767, #768, #771, #772, #773, #775, #779 Numerous improvements to project documentation.
  2. Docs are a combination of source code documentation and a programming guide. It is built as the code changes as part of the CI system, and published on procedure.kit.run with a path matching the branch. Therefore, the most up-to-date documentation is: procedure.kit.run/development, this release's documentation is at procedure.kit.run/release/4.3.0.
  3. The programming guide is written in Markdown, and stored in the repo under Documentation/Guides
  4. Documentation is generated using jazzy and organised via .jazzy.json file. It can be generated locally by running jazzy --config .jazzy.json from the project root.
  5. Because documentation is built as part of CI, it should evolve with the code, and the documentation for WIP branches can be built, published and viewed.
  6. Eventually the documentation site will allow framework consumers to browse versions of the programming guide.
  7. Current documentation coverage is 53%. This is reported in a shield on the project page.

Other Improvements

  1. #757 Improves the QualityOfService tests.
  2. #756 Fixes a rare race condition involving Condition.
  3. #752, #754 Resolves ProcedureObserver errors in Xcode 9 Beta 3 onwards.
  4. #769 Fixes a race condition in TestProcedure.
  5. #770, #774 Fixes unstable tests related to producing operations.
  6. #777 Simplifies Procedure.ConditionEvaluator state management.

Other Notes

  • I (@danthorpe) changed the code of conduct to comply with GitHub's notion of what a code of conduct is. Quite frankly, this is annoying, please feel free to contact me if you find the changes disagreeable.