Skip to content

Implement Swift 6 Approachable Concurrency migration (Stages 2–5)#144

Closed
Copilot wants to merge 20 commits intomain-actor-isolationfrom
copilot/create-separate-pull-requests
Closed

Implement Swift 6 Approachable Concurrency migration (Stages 2–5)#144
Copilot wants to merge 20 commits intomain-actor-isolationfrom
copilot/create-separate-pull-requests

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

Implements all pending stages from the plan at docs/plans/approachable-concurrency.md. Stage 1 (build settings) was already applied. Each stage is a separate commit.

Stage 2: NetworkAuthManager actor → class

With SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor, MainActor serialization replaces the actor. bearerAuthSupported() drops async, basicAuthString() drops nonisolated. Resolves Token.isValid cross-isolation warning.

Stage 3a: Remove DispatchQueue.main.async wrappers

Three locations (Alert.display, OpenViewController selection handler, SaveViewController.savePressed panel callback) — redundant under MainActor default isolation.

Stage 3b: UploadManager → async throws

// Before
func verifyConnection(authManager:completionHandler:)
func upload(profile:authMgr:siteInfo:signingIdentity:completionHandler:)

// After
func verifyConnection(authManager:) async throws -> VerificationInfo
func upload(profile:authMgr:siteInfo:signingIdentity:) async throws

Button action in UploadInfoView bridges with Task { await ... } — the one idiomatic place a Task{} remains.

Stage 3c: Model.loadExecutable → direct return

Completion handler removed since the work is synchronous. findExecutableOnComputerUsingfindExecutable, callers across TCCProfileViewController, OpenViewController updated.

Stage 3d: TCCProfileImporter → direct return

Both decodeTCCProfile overloads now throws -> TCCProfile. TCCProfileImportCompletion typealias removed. Tests updated from callback assertions to do/catch.

Stage 4: @concurrent for background I/O

  • SecurityWrapper.copyDesignatedRequirement, .sign, .loadSigningIdentities@concurrent static func ... async throws
  • Model.loadExecutable@concurrent func ... async throws -> Executable
  • Async cascades to getAppleEventChoices, getExecutableFrom, importProfile, getExecutablesFromAllPolicies and all callers

Stage 5: Swift 6 language mode

  • SWIFT_VERSION = 5.06.0 (4 build configurations)
  • SaveViewController.observeValue: nonisolated + MainActor.assumeIsolated for KVO override mismatch
  • ModelTests.setUp: same pattern for XCTestCase lifecycle mismatch

💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copilot AI and others added 7 commits March 26, 2026 20:33
With SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor, all types are MainActor
by default. The actor's synchronization purpose (single-flight token
refresh) is now provided by MainActor serialization.

Changes:
- actor NetworkAuthManager → class NetworkAuthManager
- bearerAuthSupported(): drop async (no longer needed without actor)
- basicAuthString(): drop nonisolated (no longer an actor)
- JamfProAPIClient: drop await from bearerAuthSupported() calls
- NetworkAuthManagerTests: drop await from bearerAuthSupported() calls

Side effect: Resolves Token.isValid cross-isolation warning because
Token and NetworkAuthManager are now both on MainActor.

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
With MainActor default isolation, manual dispatch to the main thread
is redundant. All three locations are already MainActor-isolated.

Changes:
- Alert.swift: Remove DispatchQueue.main.async wrapper in display()
- OpenViewController.swift: Remove wrapper in tableView selectionIndexes
- SaveViewController.swift: Remove wrapper in savePressed panel callback

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Replace Task/completion handler pattern with direct async throws methods.

Changes:
- UploadManager.verifyConnection: async throws -> VerificationInfo
- UploadManager.upload: async throws (no completion handler)
- UploadInfoView.verifyConnection: now async, uses try await
- UploadInfoView.performUpload: now async, uses try await
- Button action bridges to async with Task { await ... }

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Replace completion handler pattern with throws -> Executable since the
work is synchronous (reads bundle info and code requirements).

Changes:
- Model.loadExecutable(url:) now throws -> Executable (no completion)
- Remove LoadExecutableCompletion typealias
- findExecutableOnComputerUsing → findExecutable, returns directly
- getExecutableFrom: uses do/catch instead of completion handler
- getAppleEventChoices: uses do/catch for each loadExecutable call
- TCCProfileViewController: promptForExecutables and acceptDrop updated
- OpenViewController.prompt: updated to use try/catch

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Replace completion handler pattern with throws -> TCCProfile since
the work is synchronous (decode data, read file).

Changes:
- TCCProfileImporter.decodeTCCProfile(data:) now throws -> TCCProfile
- TCCProfileImporter.decodeTCCProfile(fileUrl:) now throws -> TCCProfile
- Remove TCCProfileImportCompletion typealias
- TCCProfileConfigurationPanel: uses try/catch in panel callback
- TCCProfileImporterTests: updated to use try/catch pattern

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Mark SecurityWrapper and Model methods with @Concurrent to move disk
I/O and security operations off MainActor onto the cooperative pool.

Changes:
- SecurityWrapper.copyDesignatedRequirement: @Concurrent async throws
- SecurityWrapper.sign: @Concurrent async throws
- SecurityWrapper.loadSigningIdentities: @Concurrent async throws
- Model.loadExecutable: @Concurrent async throws -> Executable
- Model.getAppleEventChoices: now async (calls loadExecutable)
- Model.getExecutableFrom/findExecutable: now async
- Model.getExecutablesFromAllPolicies: now async
- Model.importProfile: now async
- All callers updated to use Task/await where needed
- ModelTests: updated to async test methods

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Flip SWIFT_VERSION from 5.0 to 6.0 so all concurrency warnings become
hard errors. Fix override isolation mismatches.

Changes:
- SWIFT_VERSION = 6.0 in all 4 build configurations
- SaveViewController.observeValue: add nonisolated + MainActor.assumeIsolated
- ModelTests.setUp: add nonisolated + MainActor.assumeIsolated
- Update plan document to reflect all stages complete

Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/4235dbf5-feb0-4744-839d-543eee3b8ee5

Co-authored-by: watkyn <40115+watkyn@users.noreply.github.com>
Copilot AI changed the title [WIP] Add separate pull requests for each state in the plan Implement Swift 6 Approachable Concurrency migration (Stages 2–5) Mar 26, 2026
Copilot AI requested a review from watkyn March 26, 2026 20:45
jjpritzl and others added 12 commits March 31, 2026 12:12
* Initial plan

* Add swift-format config, GitHub Action workflow, and pre-commit hook

Co-authored-by: jjpritzl <108085430+jjpritzl@users.noreply.github.com>
Agent-Logs-Url: https://github.com/jamf/PPPC-Utility/sessions/1f5e71ff-f5b8-4e2c-8b0e-bc262951f2fd

* add-swift Disable AlwaysUseLowerCamelCase and ReplaceForEachWithForLoop rules

These rules conflict with existing codebase conventions (Logger constants,
enum-style variable names, and forEach usage patterns).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* add-swift Apply swift-format to entire codebase

One-time bulk format using xcrun swift-format --in-place -r -p .
This commit contains only formatting changes — no logic or functional changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* add-swift Fix SwiftLint conflicts with swift-format

- Disable opening_brace rule in .swiftlint.yml (conflicts with swift-format's
  multiline condition brace placement)
- Set multiElementCollectionTrailingCommas to false in .swift-format to avoid
  trailing comma conflicts with SwiftLint
- Remove trailing commas added by swift-format
- Remove superfluous swiftlint:disable file_length comment
- Fix function_body_length violations caused by array expansion

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* add-swift Increase file_length limit to 500 in .swiftlint.yml

TCCProfileViewController.swift exceeds the default 400-line limit after
swift-format expanded multi-line arrays. Raising the threshold avoids
needing inline swiftlint:disable comments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* add-swift Fix pre-commit hook to handle special characters in filenames

Use NUL-delimited output (git diff -z) with xargs -0 to safely handle
filenames containing spaces, tabs, or newlines. Pass -- before the file
list to prevent paths beginning with - from being interpreted as options.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* add-swift Remove SwiftLint — swift-format now handles all formatting

- Delete .swiftlint.yml config
- Delete .github/workflows/swiftlint.yml GitHub Action
- Remove SwiftLint build phase from Xcode project
- Remove all inline swiftlint:disable/enable comments from Swift files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jjpritzl <108085430+jjpritzl@users.noreply.github.com>
Co-authored-by: JJ Pritzl <jj.pritzl@jamf.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* AI generated removal of the big sur compatibility logic. Needs vetted and tested

* big-sur story/JPCFM-5531 Add minor changes to update minimum supported OS and remove remaining Big Sur things

* big-sur story/JPCFM-5531 Remove swiftlint disable call due to reduced file length

* big-sur story/JPCFM-5531 Add Copilot suggestion for generating test results

* big-sur story/JPCFM-5531 Add Copilot refactor to loadExecutable function

* big-sur story/JPCFM-5531 Remove code coverage addition

---------

Co-authored-by: Tony Eichelberger <tony.eichelberger@jamf.com>
* started on a claude.md and converting a couple tests

* added plan

* phase 3 done

* phase 4

* phase 5

* phase 6

* phase 7

* swift format

---------

Co-authored-by: Tony Eichelberger <tony.eichelberger@jamf.com>
@watkyn watkyn closed this Apr 2, 2026
@watkyn watkyn deleted the copilot/create-separate-pull-requests branch April 2, 2026 21:21
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.

4 participants