Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
This creates a Swift package with an example app, linting and formatting
commands, CI pipeline, README, and contributing guidelines.

In the absence of guidance or data about which minimum Swift version to
use, I decided to use the latest release at time of writing (5.10). We
can revisit this later if need be.

The SwiftLint rules are taken from our Asset Tracking repo at commit
b39e5187 (plus one tweak to a comment). They seemed like a good starting
point (I had previously done some thinking about these rules in [1]),
and we can tweak them as needed. I’ve enabled the private_swiftui_state
rule (seems useful) and also inverted its default trailing comma rule
(for compatibility with SwiftFormat).

Upon realising that SwiftLint and SwiftFormat have clashing opinions on
trailing commas, I worried that there might turn out to be other clashes
between the two. So I then hoped that we could get away with just using
SwiftLint, which does have some style rules. But it doesn’t enforce some
basic things like indentation. I hope that there aren’t further clashes
between the two tools, but we won’t find out until we write more code.

We use Mint to run SwiftLint and SwiftFormat. This allows us to lock
their versions, which we can’t do with Homebrew. It’s unfortunate that
for some reason SwiftLint takes an eternity to build using Mint, but
it’s a one-time thing per developer. I originally ran these tools as
Swift package plugins, but SwiftLint’s plugin was crashing when run in
Xcode 16 beta, hence the switch to Mint. Maybe we can switch back
sometime.

The build scripts used by CI, as well as the linting scripts, are
implemented as a Swift command-line tool. Hopefully we’ll find this
easier to maintain and modify than a set of Bash scripts. Note that in
these scripts I’m using APIs that are not available in macOS 11, which
is the package’s deployment target. I’m happy for this tool to only work
on macOS 14 (i.e. the latest at time of writing) but there doesn’t seem
to be a way to express per-target platform requirements in SPM. So
instead I’ve had to pepper the code with #available(macOS 14, *)
annotations; don’t know if there’s a better way to do it (I tried
creating a separate, nested Package.swift but Xcode refused to work with
it).

The library’s minimum supported OS versions (i.e. iOS 14 and
equivalents) are taken from Umair’s guidance [2] which I believe relates
to the accepted RFC for increasing ably-cocoa’s minimum-supported OS
versions to the same [3]. It’s not yet clear to me how we’ll guarantee
support for these versions given that, at the time of writing, the
oldest iOS simulator that you could install in the latest Xcode version
(15.4) is 15.0. For now, I’m just testing on the latest release OS
versions at time of writing.

As for which Xcode versions we test on in CI, I’m (if you ignore the
beta Xcode 16 testing) currently just testing on the oldest version of
Xcode that we support (15.3). We might want to expand this to test new
versions of Xcode as they’re released (because sometimes new compiler
warnings are introduced, I think).

I haven’t committed the `.swiftpm/configuration/Package.resolved` file
created by Xcode 16. We already have two Package.resolved files (see the
`comparePackageLockfiles` lint task) and so let’s wait for Xcode 16 to
be released to see whether this file is going to stick around (perhaps
it will become part of the .gitignore created by the SPM that ships with
Xcode 16).

[1] ably/ably-asset-tracking-swift#629
[2] https://ably.atlassian.net/wiki/spaces/SDK/pages/3261202438/Swift+Architecture+Thoughts
[3] https://ably.atlassian.net/wiki/spaces/ENG/pages/3199500291/ADR-114+Increase+Cocoa+SDK+minimum+supported+version+to+iOS+14
  • Loading branch information
lawrence-forooghian committed Aug 12, 2024
0 parents commit 5753444
Show file tree
Hide file tree
Showing 43 changed files with 1,805 additions and 0 deletions.
114 changes: 114 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Check

on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
lint:
runs-on: macos-latest

# From actions/cache documentation linked to below
env:
MINT_PATH: .mint/lib
MINT_LINK_PATH: .mint/bin

steps:
- uses: actions/checkout@v4

# We use caching for Mint because at the time of writing SwiftLint took about 5 minutes to build in CI, which is unacceptably slow.
# https://github.com/actions/cache/blob/40c3b67b2955d93d83b27ed164edd0756bc24049/examples.md#swift---mint
- uses: actions/cache@v4
with:
path: .mint
key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
restore-keys: |
${{ runner.os }}-mint-
- run: npm ci
- run: brew install mint
- run: mint bootstrap

- run: swift run BuildTool lint

generate-matrices:
runs-on: macos-latest
outputs:
matrix: ${{ steps.generation-step.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: generation-step
run: swift run BuildTool generate-matrices >> $GITHUB_OUTPUT

check-spm:
name: SPM (Xcode ${{ matrix.tooling.xcodeVersion }}, Swift ${{ matrix.tooling.swiftVersion }})
runs-on: macos-latest
needs: generate-matrices
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrices.outputs.matrix).withoutPlatform }}

steps:
- uses: actions/checkout@v4
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ matrix.tooling.xcodeVersion }}

# https://forums.swift.org/t/warnings-as-errors-for-libraries-frameworks/58393/2
- run: swift build -Xswiftc -warnings-as-errors -Xswiftc -swift-version -Xswiftc ${{ matrix.tooling.swiftVersion }}
- run: swift test -Xswiftc -warnings-as-errors -Xswiftc -swift-version -Xswiftc ${{ matrix.tooling.swiftVersion }}

check-xcode:
name: Xcode, ${{matrix.platform}} (Xcode ${{ matrix.tooling.xcodeVersion }}, Swift ${{ matrix.tooling.swiftVersion }})
runs-on: macos-latest
needs: generate-matrices

strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrices.outputs.matrix).withPlatform }}

steps:
- uses: actions/checkout@v4
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ matrix.tooling.xcodeVersion }}

- name: Build and run tests
run: swift run BuildTool build-and-test-library --platform ${{ matrix.platform }} --swift-version ${{ matrix.tooling.swiftVersion }}

check-example-app:
name: Example app, ${{matrix.platform}} (Xcode ${{ matrix.tooling.xcodeVersion }}, Swift ${{ matrix.tooling.swiftVersion }})
runs-on: macos-latest
needs: generate-matrices

strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrices.outputs.matrix).withPlatform }}

steps:
- uses: actions/checkout@v4
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ matrix.tooling.xcodeVersion }}

- name: Build example app
run: swift run BuildTool build-example-app --platform ${{ matrix.platform }} --swift-version ${{ matrix.tooling.swiftVersion }}

# We use this job as a marker that all of the required checks have completed.
# This allows us to configure a single required status check in our branch
# protection rules instead of having to type loads of different check names
# into the branch protection web UI (and keep this list up to date as we
# tweak the matrices).
all-checks-completed:
runs-on: ubuntu-latest
needs:
- lint
- check-spm
- check-xcode
- check-example-app

steps:
- name: No-op
run: "true"
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Start of .gitignore created by Swift Package Manager
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
# End of .gitignore created by Swift Package Manager

/node_modules
/.mint
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Don’t try and format the asset catalogue JSON files, which are managed by Xcode
*.xcassets/
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.10
102 changes: 102 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
excluded:
- .build

strict: true

disabled_rules:
# All of the default rules of type "metrics". We have no reason to believe that the arbitrary defaults picked by SwiftLint are helpful.
- cyclomatic_complexity
- file_length
- function_body_length
- function_parameter_count
- large_tuple
- line_length
- nesting
- type_body_length

# Rules of type "lint" that we’ve decided we don’t want:
- todo # We frequently use TODOs accompanied by a GitHub issue reference

opt_in_rules:
# All of the opt-in rules of type "performance":
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- empty_collection_literal
- empty_count
- empty_string
- first_where
- flatmap_over_map_reduce
- last_where
- reduce_into
- sorted_first_last

# Opt-in rules of type "style" that we’ve decided we want:
- attributes
- closure_end_indentation
- closure_spacing
- collection_alignment
- comma_inheritance
- conditional_returns_on_newline
- file_header
- implicit_return
- literal_expression_end_indentation
- modifier_order
- multiline_arguments
- multiline_arguments_brackets
- multiline_function_chains
- multiline_literal_brackets
- multiline_parameters
- multiline_parameters_brackets
- operator_usage_whitespace
- prefer_self_type_over_type_of_self
- self_binding
- single_test_class
- sorted_imports
- switch_case_on_newline
- trailing_closure
- trailing_newline
- unneeded_parentheses_in_closure_argument
- vertical_parameter_alignment_on_call
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces

# Opt-in rules of type "idiomatic" that we’ve decided we want:
- anonymous_argument_in_multiline_closure
- convenience_type
- fallthrough
- fatal_error_message
- pattern_matching_keywords
- redundant_type_annotation
- shorthand_optional_binding
- static_operator
- toggle_bool
- xct_specific_matcher

# Opt-in rules of type "lint" that we’ve decided we want:
- array_init
- empty_xctest_method
- missing_docs
- override_in_extension
- yoda_condition
- private_swiftui_state

file_header:
# Comments, except for the required and standard ones at the top of a Package.swift file. The aim of this rule is to make sure that we delete the Xcode-generated boilerplate comment.
forbidden_pattern: //(?! (swift-tools-version:|The swift-tools-version declares the minimum version of Swift required to build this package\.))

identifier_name:
&no_length_checks # We disable the length checks, for the same reason we disable the rules of type "metrics".
min_length:
warning: 1
max_length:
warning: 10000

type_name: *no_length_checks

generic_type_name: *no_length_checks

# For compatibility with SwiftFormat
trailing_comma:
mandatory_comma: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<true/>
</dict>
</plist>
79 changes: 79 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/AblyChat.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AblyChat"
BuildableName = "AblyChat"
BlueprintName = "AblyChat"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AblyChatTests"
BuildableName = "AblyChatTests"
BlueprintName = "AblyChatTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AblyChat"
BuildableName = "AblyChat"
BlueprintName = "AblyChat"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
10 changes: 10 additions & 0 deletions AblyChat.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions AblyChat.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
42 changes: 42 additions & 0 deletions AblyChat.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"originHash" : "f6b591fa76437494c2609ca1208b8583cbc3debe5e659be06bdcb7bc4bb5e457",
"pins" : [
{
"identity" : "ably-cocoa",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ably/ably-cocoa",
"state" : {
"revision" : "7f639c609e50053abd4590f34333f9472645558a",
"version" : "1.2.33"
}
},
{
"identity" : "delta-codec-cocoa",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ably/delta-codec-cocoa",
"state" : {
"revision" : "3ee62ea40a63996b55818d44b3f0e56d8753be88",
"version" : "1.3.3"
}
},
{
"identity" : "msgpack-objective-c",
"kind" : "remoteSourceControl",
"location" : "https://github.com/rvi/msgpack-objective-C",
"state" : {
"revision" : "3e36b48e04ecd756cb927bd5f5b9bf6d45e475f9",
"version" : "0.4.0"
}
},
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
"version" : "1.5.0"
}
}
],
"version" : 3
}
Loading

0 comments on commit 5753444

Please sign in to comment.