Migrate Tuist/Config.swift to Tuist.swift

Need/problem

Adding Tuist to a raw Xcode project requires two actions, creating a Tuist directory at the root, and then placing a Config.swift. It’s not too many steps, but I think we can remove some friction by turning that into a one-action step: creating a Tuist.swift at the root. You’d end up with the following directory structure:

Tuist/ (optional)
Tuist.swift
Project.xcodeproj

Motivation

We are loosening the dependency between Tuist features and Tuist projects by making some features work with raw Xcode projects. This decision acknowledges the idea that Apple might advance vanilla Xcode projects (we saw a bit of that in Xcode 16 and synchronised file groups) and opens up some Tuist features to more users (e.g. previews). With that in mind, I think it’s important that we keep the friction of adopting Tuist, to its minimum.

There’s also the marketing piece of it. Seeing a Tuist.swift at the root is like seeing a Fastfile or a Podfile or a Package.swift. It signals something about the project, so the closer to the root those files are, the easier it is to realise that the project is integrating with Tuist.

Detailed design

We should implement this in a backward-compatible manner:

  • It extends the logic that does the look-up of the root by traversing to accept both, Tuist/Config.swift and Tuist.swift as valid patterns.
  • In the case of Tuist/Config.swift we can show a warning to tell developers about the change and suggest the steps that they need to take themselves.
  • The structure of the file doesn’t change.
  • In the next major version we can then drop support for Tuist/Config.swift but I think this will be very far in the future, and by the time we do it, most users will mostly have migrated to the new convention.

Drawbacks

  • People might get annoyed by this move when look through the lenses of “what value does this bring to my project?”
  • We might introduce a regression if we have some logic that implicitly depends on the old convention. I’m confident this won’t happen since we have many acceptance and unit tests in that logic.

Alternatives

Leaving things as they are?

Adoption strategy

They’ll get a warning with a link to the documentation that captures the reason for the change and the steps that they need to take to migrate. Tuist features will continue to work, so they’ll have plenty of time to decide when is the right time to do the move.

How we teach this

  • A warning in the CLI if we detect the old convention.
  • The release notes including a link to this topic
  • The documentation and fixtures
1 Like

I’m onboard with moving to Tuist.swift. But I would take this opportunity to also rethink the Config.swift API – primarily, to divide configuration for Tuist projects and for raw Xcode projects, so it’s obvious which properties are meant for which setup. It might be good to sketch out how that would like in this RFC.

I like the idea. Before I go ahead with an RFC, do you have any idea of how the separation could look? I haven’t put that much thinking into it yet, so I’m just curious if you’ve formed some shape in your mind already.

I’d keep configuration that’s common across raw Xcode projects and Tuist projects in the root.

Current Config.swift example:

import ProjectDescripotion

let config = Config(
  fullHandle: "tuist/tuist",
  generationOptions: .options(...)
)

Possible Tuist.swift API:

import ProjectDescription

let tuist = Tuist(
  fullHandle: "tuist/tuist",
  projectsConfiguration: .projectsConfiguration(
   generationOptions: .options(...)
  )
)

Where I’m not fully satisfied with the projectsConfiguration name. It should signal it’s for Tuist projects only. Alternative name could be tuistProjectsConfiguration or tuistProjectsOptions. Any ideas?

Or maybe just project?

Tuist project

import ProjectDescription

let tuist = Tuist(
  fullHandle: "tuist/tuist",
  project: .tuist(....)
)

Vanilla Xcode project

import ProjectDescription

let tuist = Tuist(
  fullHandle: "tuist/tuist",
  project: .xcode(....)
)

I like it, let’s do that :raised_hands:

This only makes sense if the contents of Workspace.swift and Project.swift can be included inside Tuist.swift otherwise the root is going to be:

Tuist/
Tuist.swift
Workspace.swift

Having 3 Tuist related items at the root with no advantage.

Merging Tuist Projects manifests into Tuist.swift is something I doubt we’ll do because the role of Tuist.swift is configuring Tuist features, not declaring projects. For those cases we have the manifest files: Project.swift, Workspace.swift, helpers…