Evitando conflitos no Xcode

raafas

Rafael Leandro

Posted on October 15, 2021

Evitando conflitos no Xcode

Introdução

O objetivo desse texto é mostrar como resolvi alguns problemas no meu time utilizando o Tuist para gerar projetos e workspaces do Xcode e que com isso nós evitamos conflitos na hora do merge, resolvemos problemas para gerenciar dependências e também podemos padronizar configurações dos projetos e abrir individualmente o projeto que vai ser alterado (modo foco).

Instalação

A instalação é muito simples, basta executar o comando no terminal:
curl -Ls https://install.tuist.io | bash

Criando um projeto novo

Se for um novo projeto a utilização do Tuist é super simples.
Basta criar uma pasta e executar o tuist init

mkdir MyApp
cd MyApp
tuist init --platform ios
Enter fullscreen mode Exit fullscreen mode

O comando init irá gerar os arquivos base, Info.plist, AppDelegate.swift, arquivos de teste e o Project.swift que contém as configurações do projeto.

Migrando um projeto existente

A migração no meu caso foi tranquila porque o projeto é simples e tenho um Workspace com vários projetos que dependem do Core e uma única dependência externa em um Target de teste.

Comecei migrando o Core, porque precisava definir a dependência dele nos outros projetos, resolvi todas as outras dependências e por último configurei o Workspace.
Na pasta de cada projeto criei o arquivo Project.swift, no diretório raíz o Workspace.swifte a pasta Tuist com o arquivo Dependencies.swift

Configurações do projeto

O Project.swift contém a configuração do projeto. É nesse arquivo onde são definidos nome, organização, targets, schemas, entre outras coisas.

Comecei fazendo o import do framework ProjectDescription esse arquivo deve inicializar uma variável do tipo Project que pode ter qualquer nome, mas a recomendação da documentação é nomear como project mesmo.

Um project precisa obrigatoriamente dos parâmetros: name e targets que é um array do tipo Target.

No Target é especificado o nome, plataforma, tipo do produto, bundle e os arquivos de código.

let target = Target(name: "App",
                    platform: .iOS,
                    product: .app,
                    bundleId: "com.rafa.example",
                    infoPlist: "Info.plist",
                    sources: "Sources/**",
                    dependencies: [])
Enter fullscreen mode Exit fullscreen mode
let project = Project(
    name: "MyProject",
    targets: [target]
)
Enter fullscreen mode Exit fullscreen mode

Dependências externas

A integração com dependências externas ainda está em alpha, como é avisado na documentação

No momento que estou escrevendo esse texto a integração com Cocoapods ainda não é suportada.

Cada projeto pode ter suas dependências configuradas individualmente, basta criar a pasta Tuist com o arquivo Dependencies.swift dentro dela.
No meu caso, fiz isso na pasta raiz do projeto porque tenho uma única dependência externa.

import ProjectDescription

let dependencies = Dependencies(
    carthage: [
        .github(path: "Alamofire/Alamofire", requirement: .exact("5.0.4")),
    ],
    swiftPackageManager: [
        .remote(url: "https://github.com/Alamofire/Alamofire", requirement: .upToNextMajor(from: "5.0.0")),
    ],
    platforms: [.iOS]
)
Enter fullscreen mode Exit fullscreen mode

Feito isso baixe as dependências rodando
tuist dependencies fetch. Uma pasta chamada Dependencies será criada e o código será baixado nela.

De volta ao Project.swift é necessário registrar no Target a dependência baixada.

let target = Target(name: "App",
                    platform: .iOS,
                    product: .app,
                    bundleId: "com.rafa.example",
                    infoPlist: "Info.plist",
                    sources: "Sources/**",
                    dependencies: [
                .external(name: "Alamofire"),
            ])
Enter fullscreen mode Exit fullscreen mode

Configurações do Workspace

Por padrão o tuist generate cria um Workspace com o mesmo nome do projeto e já inclui as dependências.
No meu caso os projetos estão num monorepo, então preciso configurar um Workspace e adicionar todos os projetos nele.

import ProjectDescription

let workspace = Workspace(
    name: "ProjectWorkspace",
    projects: [
        "Project1",
        "Project2",
        "Project3"
    ],
    schemes: []
)
Enter fullscreen mode Exit fullscreen mode

Por padrão os schemas são gerados automaticamente, mas podem ser personalizados para configurar as ações de cada um.

Gerando os arquivos

A configuração é essa, dependendo do tamanho do projeto pode ser um pouco cansativa mas os ganhos são compensatórios.

Depois de tudo configurado, é só rodar o tuist dependencies fetch para baixar as dependências e depois tuist generate para gerar os projetos/workspaces.

Testei outras ferramentas mas resolvi adotar o Tuist por utilizar Swift e não Yaml, possibilidade de fazer cache dos módulos, cache dos testes, screenshot de dependências e por considerar a adoção fácil no projeto em que trabalho.
Finalizei implementando o xcdiff evitando que o .xcodeproj fosse alterado manualmente.

E é isso! :)

Links úteis

Tuist.io
Tuist docs
xcdiff

💖 💪 🙅 🚩
raafas
Rafael Leandro

Posted on October 15, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Evitando conflitos no Xcode
ios Evitando conflitos no Xcode

October 15, 2021