Need/problem
Developers in the Swift ecosystem want to write their automation in Swift.
Motivation
Automation has always been possible within Xcode, even in Objective-C times. Automation can be materialized as an executable (or multiple) whose execution can be controlled through flags and arguments. Executables have existed for a long time.
However, an important piece was missing: the ability to encapsulate units of automation and reuse them across workflows. This is something that Swift Package Manager addressed, but while required, it was not sufficient for people to make the switch from Fastlane to a solution that uses the language that they are familiar with. In my opinion, three elements are necessary for that to happen:
- An extensive foundation of packages and utilities upon which to build workflows. Swift is behind there compared to other ecosystems, but it’s slowly catching up with the community investing more in server-side Swift, and also organizations like ours investing in utilities like Command or FileSystem.
- A directory of resources, packages, and examples where people can learn how to build their automation. It needs to be something oriented towards automation and not that much towards how to use Swift in the context of servers or building apps.
- And last, a solution to ensure workflows run as instantly as they can to align with the expectations that developers have when they run Ruby or bash scripts. They launch instantly! This is where Tuist can bring a lot to the table by leveraging years of investment in a caching solution that works with external packages.
I propose that Tuist lead a change there that goes beyond the technical work in this document. I think it’s time for a change and to meet developers eager to use Tuist for automation.
Detailed design
I propose extending our current project directory structure model, to account for a new type of manifest file, workflows.
A workflow represents a unit of automation (i.e. a lane
). They live under the Tuist/Workflows
directory:
Tuist/
Workflows/
Build.swift
Test.swift
MyProject.xcodeproj
Workflows can be invoked through tuist workflows run {name}
where {name}
is the dash-cased version of the workflow name. Workflows are editable with tuist edit
and are included by default in the generated projects if developers are using Tuist Projects. Every workflow is represented by an Xcode scheme named Workflow - {name}
so developers can run them directly from Xcode and debug them using tools like LLDB.
Developers can depend on third-party package dependencies. Those are declared in either a Package.swift
or a Tuist/Package.swift
file, and reference to from a Tusit/Workflows.swift
file with the following structure:
import WorkflowDescription
let workflows = Workflows(dependencies: [
"FileSystem",
"AppStoreConnect"
])
By doing the above, we can bind workflows to the external dependencies they depend on, and not only that, thanks to our binary caching functionality, developers don’t need to compile their external dependencies, just their workflow files, which we expect to be compilable in a matter of seconds.
We’ll migrate our existing scripts to workflows for dogfooding purposes and work on putting resources (examples, blog posts, and packages) to nudge the community toward adopting workflows.
A note on the workflow DSL
This is a bit TDB at the moment. I’d like to create something tangible first so that I can get a better grasp of what a good interface would be.
Drawbacks
- It’s an extra surface to maintain, which would stretch us. However, I don’t expect much maintenance once the feature is built.
- Some organizations have started using Bash as a substitute for Fastlane. However, bash is not straightforward to write and doesn’t support re-using units of business logic like developers would be able to do through SPM.
- Developers could use a Swift Package to model workflows (it’s just an executable). However, going through the compilation cycles, especially once the automation logic grows and the workflows depend on a handful of dependencies, can add significant time to every CI build.
Alternatives
- Bash scripts that Tuist can show and invoke. However, developers can’t share or reuse units of automation business logic built by other developers.
- Swift Package. As mentioned above, we think it makes more sense to have an Xcode-native graph that we can cache and compile right after opening it in Xcode without depending on some asynchronous activity within Xcode.
Adoption strategy
New Tuist projects
They’ll come with a default workflow:
Tuist/
Workflows.swift
Workflows/
Example.swift
Tuist.swift
Project.swift
Existing Tuist projects
They can run tuist workflows setup
, and we’ll create the workflow scaffold for them.
Xcode projects
They can also run tuist workflows setup
, and we’ll create a Tuist.swift
file at the project’s root.
How we teach this
We should leverage the following tools for education:
- Documentation: We’ll include content documenting the feature and also get started guidelines for people who have heard about “Tuist Workflows” and want to give it a shot without getting distracted by other Tuist capabilities.
- Blog posts: We can write blog posts and help some community projects transition to this new automation model. We can do the work for them and publish case studies at the end of the work.