Creating and Distributing Swift Packages

How to start writing and sharing your Swift code using Swift Package Manager, Github, and Travis-CI

Note: This tutorial assumes you’re using Swift 4.1 or higher.

Recently while working on a SwiftNIO side-project I ended up writing a few classes for handling IP addresses and networks. Since the functionality and scope of these classes was nice and contained, I thought it might be a good idea to publish the package so I could use it in other projects.

As I’d never done this before and didn’t see a huge number of resources online for the subject, I figured it might make for a good read for others starting out with Swift. In this post I’ll show you how to create your own Swift package that can be both on macOS and linux. I’ll also look at how to leverage Github and Travis-CI to automate your testing and deployment.

Swift Package Manager

First we need to take a look at the Swift Package Manager. If you’ve done much Server-side Swift development, you’ve probably seen the Package.swift file included in every project, and you’ve likely run commands like swift package resolve to keep your dependencies in order.

The Swift Package Manager is a tool for managing distribution of source code, aimed at making it easy to share your code and reuse others’ code. The tool directly addresses the challenges of compiling and linking Swift packages, managing dependencies, versioning, and supporting flexible distribution and collaboration models.

This time we’ll be looking at the Swift Package Manager from the other direction — creating a new library that others can import.

Getting Started

For this tutorial I’ll be creating a very simple library that adds back a bit of functionality that was removed in Swift 3, support for ++ and -- operators (Take that, Chris Lattner 😉).

Create a new directory

The very first step is to create a new directory to save our project in. Pick your name carefully as the name of the directory will be used as the default name of the package. I’ll go with Incrementer .

Create the Template

The next thing we’ll do is create a package template to get started with. Conveniently, Apple has done all the heavy lifting here.

Assuming you have a Swift 4.0 or greater, simply run the following command and the Swift Package Manager will create a new, mostly empty package template.

Run the Tests

A good way to check that the template has been created successfully is to try running the unit tests. You can do this by running the following command.

Create an XCode Project (optional)

You may have noticed if you already tried to open this project in XCode that an error is returned preventing you from opening the project as your normally would. That’s because there’s no project file yet. You can run the following command to create one.

Once that command has completed you can open the project in XCode by running:

The Code

At this point you should have a file named Incrementer.swift within the Sources directory in your base directory. Open that file and add the following code.

This little bit of code will make up the bulk of our package. These extensions should allow for you to use the ++ and —- postfix operators anywhere you have imported the package.

For the sake of completeness I’ll also examine some of the less common annotations, statements, and syntax used in this example.

A defer statement is used for executing code just before transferring program control outside of the scope that the defer statement appears in.
public enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module
static is used to designate type methods (methods of struct, enum, etc.). static also marks that the definition is final and cannot be overridden by subclasses.
postfix is used to define an operator that follows its target. Whereas prefix (not used here) is used to define an operator that precedes its target.
@discardableResult this attribute suppresses the compiler warning when the function or method that returns a value is called without using its result.

Unit Tests

While you may not feel that unit tests are necessary for your personal projects, when sharing an open-source package with the world it’s probably a good idea to write some tests to ensure the code you’re sharing will actually do what it’s supposed to. You can add the following code to IncrementerTests.swift within the/Tests/IncrementerTests directory.

Publishing to Github

Now that we’ve added the code to implement our new operators and we have unit tests to make sure they’re working, it’s time to publish the package the Github.

Note: This section assumes you are familiar with basic git commands and have a Github account.
  1. Create a new public repo in Github.
  2. Initialize a new git repo for your Package.
  3. Add your Github repo as a new remote repo.
  4. Push your changes to Github.

Finally, once your changes have been pushed to Github, the last step is to create a release so that your users can specify which version of the package they wish to use. You can follow this guide for creating releases.

Setting up CI/CD with Travis-CI

This is extra work, but if you plan on supporting a package long-term, I highly recommend it.

Travis-CI is a free (for open-source) tool that links to your Github account and allows you to run test and deployment jobs that are triggered when you push new code.

  1. Log into Travis-CI using your Github account.
  2. Find your package repo in the Travis-CI UI and enable builds for the repo.
  3. Create an empty .travis.yml file and add it to your working directory.
  4. Populate the your .travis.yml file with the following

5. In Github, create a Personal Access Token.

6. In your base directory, install the Travis command line client. Note: this tool requires you have ruby installed.

7. Using the Travis command line tool, add your Github Personal Access Token as an encrypted environment variable. After you run the command below you should see a new value was added to env.global in your .travis.yml file.

8. (Optional) Add a build-status badge to your Package’s README file.

9. Commit and push the new code to Github. Assuming all is working correctly, you should see a new build running in the Travis UI and once the build completes you should see a new Release in Github.

A new Release in Github and a passing build in Travis-CI

Using your new Package

Once published, using your new package in other projects couldn’t be easier. Once you’ve created a new Swift project with its own Package.swift file you can just add your package’s Github repo under dependencies.

Remember, anytime you modify your Package.swift file you’ll need to refresh the dependencies. You can do so by running:

Conclusion

With Swift’s powerful new inclusion of the Swift Package Manager in Swift 4 and the ability to leverage Github and Travis-CI as part of your deployment pipeline, publishing an open-source Swift package has never been easier!

You can view my example package here.