├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .spi.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── Template │ ├── Documentation.docc │ └── Template.md │ └── Template.swift └── Tests └── TemplateTests └── TemplateTests.swift /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [mattmassicotte] 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - 'README.md' 9 | - 'CODE_OF_CONDUCT.md' 10 | - '.editorconfig' 11 | - '.spi.yml' 12 | pull_request: 13 | branches: 14 | - main 15 | 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | test: 22 | name: Test 23 | runs-on: macOS-15 24 | timeout-minutes: 30 25 | env: 26 | DEVELOPER_DIR: /Applications/Xcode_16.3.app 27 | strategy: 28 | matrix: 29 | destination: 30 | - "platform=macOS" 31 | - "platform=macOS,variant=Mac Catalyst" 32 | - "platform=iOS Simulator,name=iPhone 16" 33 | - "platform=tvOS Simulator,name=Apple TV" 34 | - "platform=watchOS Simulator,name=Apple Watch Series 10 (42mm)" 35 | - "platform=visionOS Simulator,name=Apple Vision Pro" 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Test platform ${{ matrix.destination }} 39 | run: set -o pipefail && xcodebuild -scheme Template -destination "${{ matrix.destination }}" test | xcbeautify 40 | 41 | linux_test: 42 | name: Test Linux 43 | runs-on: ubuntu-latest 44 | timeout-minutes: 30 45 | strategy: 46 | matrix: 47 | swift-version: 48 | - 6.0.3 49 | - 6.1 50 | steps: 51 | - name: Checkout 52 | uses: actions/checkout@v4 53 | - name: Swiftly 54 | uses: vapor/swiftly-action@v0.2.0 55 | with: 56 | toolchain: ${{ matrix.swift-version }} 57 | - name: Test 58 | run: swift test 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: [Template] 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, caste, color, religion, or sexual 11 | identity and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the overall 27 | community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or advances of 32 | any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email address, 36 | without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | support@chimehq.com. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series of 87 | actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or permanent 94 | ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within the 114 | community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 2.1, available at 120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 121 | 122 | Community Impact Guidelines were inspired by 123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 127 | [https://www.contributor-covenant.org/translations][translations]. 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 131 | [Mozilla CoC]: https://github.com/mozilla/diversity 132 | [FAQ]: https://www.contributor-covenant.org/faq 133 | [translations]: https://www.contributor-covenant.org/translations 134 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Matt Massicotte 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 6.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Template", 7 | platforms: [ 8 | .macOS(.v10_15), 9 | .iOS(.v12), 10 | .tvOS(.v12), 11 | .watchOS(.v5), 12 | .macCatalyst(.v13), 13 | .visionOS(.v1), 14 | ], 15 | products: [ 16 | .library(name: "Template", targets: ["Template"]), 17 | ], 18 | targets: [ 19 | .target( 20 | name: "Template" 21 | ), 22 | .testTarget( 23 | name: "TemplateTests", 24 | dependencies: ["Template"] 25 | ), 26 | ] 27 | ) 28 | 29 | let swiftSettings: [SwiftSetting] = [ 30 | .swiftLanguageMode(.v5), 31 | .enableExperimentalFeature("StrictConcurrency"), 32 | .enableUpcomingFeature("DisableOutwardActorInference"), 33 | .enableUpcomingFeature("GlobalActorIsolatedTypesUsability"), 34 | .enableUpcomingFeature("InferSendableFromCaptures"), 35 | ] 36 | 37 | for target in package.targets { 38 | var settings = target.swiftSettings ?? [] 39 | settings.append(contentsOf: swiftSettings) 40 | target.swiftSettings = settings 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | [![Build Status][build status badge]][build status] 4 | [![Platforms][platforms badge]][platforms] 5 | [![Documentation][documentation badge]][documentation] 6 | 7 |
8 | 9 | # PackageTemplate 10 | A template for Swift packages on GitHub 11 | 12 | It is a little **opinionated**, but mostly just stuff that I've found useful. Feel free to customize as needed. And if you have ideas for ways to improve this, open an issue or PR! 13 | 14 | ## Repository Details 15 | 16 | ### Naming 17 | 18 | The golden rule: your package name should **not** be the same as a public type within your package. This can result in a ridiculous situation where the compiler cannot distinguish between the module name and type name, and has made my life difficult in the past. Someone please send me a blog post or something about this and I will link to it. 19 | 20 | I'm a fan of CapitalCase. I don't think the word "Swift" should be in the name. 21 | 22 | ### Turn off "Packages" and "Deployments" 23 | 24 | Neither of them currently apply to Swift 25 | 26 | ### Branch protection 27 | 28 | GitHub offers a lot of control here. I've started doing a bare minimum: protecting the `main` branch from accidental force pushes and deletion. You can do this easily with Settings > Code and automation > Branches. Add a rule for `main` with all check boxes unchecked and done. 29 | 30 | ## Metadata 31 | 32 | ### License 33 | 34 | This is non-optional. Many users, for very valid reasons, will not even look at a package without a license. GitHub makes this easy. I have been a long-time user of the BSD 3-clause license. It is very permissive, like MIT, but also specifically limits implicit endorsements from those involved. 35 | 36 | I'm, in general, not a fan of viral licenses, especially when that virality applies to linking. However, I appreciate why that was designed the way it was. Preventing open source abuse and exploitation is important and your choice of license can really matter there. 37 | 38 | ### Code of Conduct 39 | 40 | "Let's be excellent to each other" is great! But, having a concrete set of rules about what that actually means, and what happens should those rules be broken is important. The [Contributor Covenant](https://www.contributor-covenant.org) has become popular and I think it is a great choice. 41 | 42 | ### Badges 43 | 44 | I like throwing a few badges up on my repos to provide some glanceable information. I think it is easy to go overboard here, but you should also feel good about making this your own! 45 | 46 | ### Install Instructions 47 | 48 | Many people find explicit package installation instructions helpful, even just for convenient copy-paste into another `Package.swift` file. I like to include them, but you have to watch out for two things. 49 | 50 | - you should regularly bump your version number 51 | - packages that contain a library of a different name need a more-explicit dependency specification 52 | 53 | ```swift 54 | dependencies: [ 55 | .package(url: "https://github.com/ChimeHQ/PackageTemplate", from: "1.0.0") 56 | ], 57 | targets: [ 58 | .target( 59 | name: "UseCoreFunctionality", 60 | dependencies: ["PackageTemplate"] 61 | ), 62 | .target( 63 | name: "UsesDifferentProduct", 64 | dependencies: [.product(name: "AnotherProduct", package: "PackageTemplate")] 65 | ), 66 | ] 67 | ``` 68 | 69 | ### Funding 70 | 71 | If you are using GitHub sponsorships, you know how this works. But just in case, please **do not** copy my `.github/FUNDING.yml` into your own project. 72 | 73 | ## Package.swift 74 | 75 | ### Platforms 76 | 77 | For a long time, I thought leaving platforms empty was the most compatible thing to do. However, this leaves the effective platform/version up to the compiler. And, that can produce surprising results that change over time. Being explicit is best. 78 | 79 | ### Swift 6.0 80 | 81 | Personally, I have found maintaining support for Swift 5 *compiler* extremely hard. Swift 6 has been out for a while, and I think it is ok to move along. 82 | 83 | However, you might want to remain in the Swift 5 *language mode*. So. I've made that the default here. But if you do decide to go to 6 mode, you can just delete everything here. 84 | 85 | ```swift 86 | let swiftSettings: [SwiftSetting] = [ 87 | .swiftLanguageMode(.v5), 88 | .enableExperimentalFeature("StrictConcurrency"), 89 | .enableUpcomingFeature("DisableOutwardActorInference"), 90 | .enableUpcomingFeature("GlobalActorIsolatedTypesUsability"), 91 | .enableUpcomingFeature("InferSendableFromCaptures"), 92 | ] 93 | 94 | for target in package.targets { 95 | var settings = target.swiftSettings ?? [] 96 | settings.append(contentsOf: swiftSettings) 97 | target.swiftSettings = settings 98 | } 99 | ``` 100 | 101 | I got this idea from [Keith Harrison](https://useyourloaf.com/blog/strict-concurrency-checking-in-swift-packages/). 102 | 103 | ## GitHub Actions 104 | 105 | GitHub actions are mostly great. They have gotten better about releasing new macOS versions. But, it's still worth rememebering that 106 | "macOS-latest" may not actually be the released version. However, they are fairly good about keeping newer Xcode versions available. 107 | 108 | The second problem is simulator names change and `xcodebuild` makes it very hard to not care. 109 | 110 | I have given up relying on defaults here, and I always make things explicit. Unfortunately this means manual maintenance, especially around WWDC. 111 | 112 | - Host OS 113 | - Xcode version 114 | - Simulators names 115 | 116 | If you have tricks/hacks/custom actions to make this better, **please** let me know. 117 | 118 | Note! If your package contains more than one entry it its `products` array, you'll need to append `-Package` to the scheme name to get `xcodebuild` tests to work. 119 | 120 | This stuff also matters for Linux builds, if you want to run them. I use [swiftly-action](https://github.com/vapor/swiftly-action) for this, but hopefully one day [swiftly](https://github.com/swiftlang/swiftly) is just built into the GitHub action runner images. keep the Swift version here the same as whatever comes with the Xcode version I'm using. 121 | 122 | ## Swift Package Index 123 | 124 | The [SPI](https://swiftpackageindex.com) is a no-brainer. 125 | 126 | ### Discoverability 127 | 128 | If I have an idea for a library, I always do some searching on SPI first. 129 | 130 | ### Build Checks 131 | 132 | Kind of like a mini CI. SPI will build your packages for many swift/platform combinations. I think making it clear up front what platforms your package supports is very useful. 133 | 134 | ### Hosted Documentation 135 | 136 | Perhaps the most underrated feature. If you include DocC in your package, SPI will **host** it for you. You need a `.spi.yml` file for this to work. 137 | 138 | ## Style 139 | 140 | For a very long time, I thought tabs vs spaces was a stupid thing to get worked up about. Then one day I learned that tabs can offer [accessibility improvements](https://adamtuttle.codes/blog/2021/tabs-vs-spaces-its-an-accessibility-issue/) for low-vision people. And that same advantage also helps to style code the way people prefer. So I switched to tabs and I encourage you to do same. 141 | 142 | Xcode supports [editorconfig](https://editorconfig.org), and I think including it is a great idea. 143 | 144 | ## Contributing and Feedback 145 | 146 | I'd love to hear from you! Get in touch via [mastodon](https://mastodon.social/@mattiem), an issue, or a pull request. 147 | 148 | By participating in this project you agree to abide by the [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 149 | 150 | [build status]: https://github.com/mattmassicotte/PackageTemplate/actions 151 | [build status badge]: https://github.com/mattmassicotte/PackageTemplate/workflows/CI/badge.svg 152 | [platforms]: https://swiftpackageindex.com/mattmassicotte/PackageTemplate 153 | [platforms badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmattmassicotte%2FPackageTemplate%2Fbadge%3Ftype%3Dplatforms 154 | [documentation]: https://swiftpackageindex.com/mattmassicotte/PackageTemplate/main/documentation 155 | [documentation badge]: https://img.shields.io/badge/Documentation-DocC-blue 156 | -------------------------------------------------------------------------------- /Sources/Template/Documentation.docc/Template.md: -------------------------------------------------------------------------------- 1 | # ``Template`` 2 | 3 | Summary 4 | 5 | ## Overview 6 | 7 | Text 8 | 9 | ## Topics 10 | 11 | ### Group 12 | 13 | - ``Template`` 14 | -------------------------------------------------------------------------------- /Sources/Template/Template.swift: -------------------------------------------------------------------------------- 1 | // The Swift Programming Language 2 | // https://docs.swift.org/swift-book 3 | -------------------------------------------------------------------------------- /Tests/TemplateTests/TemplateTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Template 3 | 4 | final class TemplateTests: XCTestCase { 5 | func testExample() throws { 6 | // XCTest Documentation 7 | // https://developer.apple.com/documentation/xctest 8 | 9 | // Defining Test Cases and Test Methods 10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods 11 | } 12 | } 13 | --------------------------------------------------------------------------------