Ir al contenido

Migrar un proyecto de Xcode

A menos que crees un nuevo proyecto con Tuist, en cuyo caso todo se configura automáticamente, tendrás que definir tus proyectos de Xcode usando las primitivas de Tuist. Lo tedioso de este proceso depende de la complejidad de tus proyectos.

Como probablemente sabes, los proyectos de Xcode pueden volverse desordenados y complejos con el tiempo: grupos que no coinciden con la estructura de directorios, archivos compartidos entre targets o referencias a archivos que ya no existen (por mencionar algunos). Toda esa complejidad acumulada dificulta ofrecer un comando que migre proyectos de forma fiable.

Además, la migración manual es un excelente ejercicio para limpiar y simplificar tus proyectos. No solo lo agradecerán los desarrolladores de tu equipo, sino también Xcode, que procesará e indexará los proyectos más rápido. Una vez que hayas adoptado Tuist por completo, se asegurará de que los proyectos estén definidos de manera consistente y sigan siendo sencillos.

Para facilitar ese trabajo, te ofrecemos algunas pautas basadas en el feedback que hemos recibido de los usuarios.

Crear el andamiaje del proyecto#

En primer lugar, crea el andamiaje de tu proyecto con los siguientes archivos de Tuist:

javascript
import ProjectDescription
let tuist = Tuist()
javascript
import ProjectDescription
let project = Project(
name: "MyApp-Tuist",
targets: [
/** Targets will go here **/
]
)
javascript
// swift-tools-version: 5.9
import PackageDescription
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(
// Customize the product types for specific package product
// Default is .staticFramework
// productTypes: ["Alamofire": .framework,]
productTypes: [:]
)
#endif
let package = Package(
name: "MyApp",
dependencies: [
// Add your own dependencies here:
// .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
// You can read more about dependencies here: https://docs.tuist.io/documentation/tuist/dependencies
]
)

Project.swift es el archivo de manifiesto donde definirás tu proyecto, y Package.swift es el archivo de manifiesto donde definirás tus dependencias. El archivo Tuist.swift es donde puedes definir ajustes de Tuist con alcance de proyecto.

Nombre del proyecto con sufijo -Tuist

Para evitar conflictos con el proyecto de Xcode existente, recomendamos añadir el sufijo -Tuist al nombre del proyecto. Puedes eliminarlo una vez que hayas migrado completamente tu proyecto a Tuist.

Compilar y probar el proyecto de Tuist en CI#

Para garantizar que la migración de cada cambio sea válida, recomendamos ampliar tu integración continua para compilar y probar el proyecto generado por Tuist a partir de tu archivo de manifiesto:

bash
tuist install
tuist generate
xcodebuild build {xcodebuild flags} # or tuist test

Extraer los ajustes de compilación del proyecto en archivos .xcconfig#

Extrae los ajustes de compilación del proyecto a un archivo .xcconfig para que el proyecto sea más ligero y fácil de migrar. Puedes usar el siguiente comando para extraer los ajustes de compilación del proyecto a un archivo .xcconfig:

bash
mkdir -p xcconfigs/
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -x xcconfigs/MyApp-Project.xcconfig

Luego actualiza tu archivo Project.swift para que apunte al archivo .xcconfig que acabas de crear:

swift
import ProjectDescription
let project = Project(
name: "MyApp",
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"), // [!code ++]
.release(name: "Release", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"), // [!code ++]
]),
targets: [
/** Targets will go here **/
]
)

Después amplía tu pipeline de integración continua para ejecutar el siguiente comando y asegurar que los cambios en los ajustes de compilación se realicen directamente en los archivos .xcconfig:

bash
tuist migration check-empty-settings -p Project.xcodeproj

Extraer las dependencias de paquetes#

Extrae todas las dependencias de tu proyecto al archivo Tuist/Package.swift:

swift
// swift-tools-version: 5.9
import PackageDescription
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(
// Customize the product types for specific package product
// Default is .staticFramework
// productTypes: ["Alamofire": .framework,]
productTypes: [:]
)
#endif
let package = Package(
name: "MyApp",
dependencies: [
// Add your own dependencies here:
// .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
// You can read more about dependencies here: https://docs.tuist.io/documentation/tuist/dependencies
.package(url: "https://github.com/onevcat/Kingfisher", .upToNextMajor(from: "7.12.0")) // [!code ++]
]
)
Tipos de producto

Puedes sobrescribir el tipo de producto de un paquete específico añadiéndolo al diccionario productTypes dentro de la estructura PackageSettings. Por defecto, Tuist asume que todos los paquetes son frameworks estáticos.

Determinar el orden de migración#

Recomendamos migrar los targets desde el que tiene más dependencias hacia el que tiene menos. Puedes usar el siguiente comando para listar los targets de un proyecto, ordenados por el número de dependencias:

bash
tuist migration list-targets -p Project.xcodeproj

Comienza a migrar los targets desde la parte superior de la lista, ya que son los que más dependen de otros.

Migrar targets#

Migra los targets uno a uno. Recomendamos crear una pull request por cada target para garantizar que los cambios se revisen y prueben antes de fusionarlos.

Extraer los ajustes de compilación del target en archivos .xcconfig#

Al igual que hiciste con los ajustes de compilación del proyecto, extrae los ajustes de compilación del target a un archivo .xcconfig para que el target sea más ligero y fácil de migrar. Puedes usar el siguiente comando para extraer los ajustes de compilación del target a un archivo .xcconfig:

bash
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -t TargetX -x xcconfigs/TargetX.xcconfig

Definir el target en el archivo Project.swift#

Define el target en Project.targets:

swift
import ProjectDescription
let project = Project(
name: "MyApp",
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/Project.xcconfig"),
.release(name: "Release", xcconfig: "./xcconfigs/Project.xcconfig"),
]),
targets: [
.target( // [!code ++]
name: "TargetX", // [!code ++]
destinations: .iOS, // [!code ++]
product: .framework, // [!code ++] // or .staticFramework, .staticLibrary...
bundleId: "dev.tuist.targetX", // [!code ++]
sources: ["Sources/TargetX/**"], // [!code ++]
dependencies: [ // [!code ++]
/** Dependencies go here **/ // [!code ++]
/** .external(name: "Kingfisher") **/ // [!code ++]
/** .target(name: "OtherProjectTarget") **/ // [!code ++]
], // [!code ++]
settings: .settings(configurations: [ // [!code ++]
.debug(name: "Debug", xcconfig: "./xcconfigs/TargetX.xcconfig"), // [!code ++]
.debug(name: "Release", xcconfig: "./xcconfigs/TargetX.xcconfig"), // [!code ++]
]) // [!code ++]
), // [!code ++]
]
)
Targets de tests

Si el target tiene un target de tests asociado, deberías definirlo también en el archivo Project.swift repitiendo los mismos pasos.

Validar la migración del target#

Ejecuta tuist generate seguido de xcodebuild build para asegurar que el proyecto compila, y tuist test para asegurar que los tests pasan. Además, puedes usar xcdiff para comparar el proyecto de Xcode generado con el existente y verificar que los cambios sean correctos.

Repetir#

Repite hasta que todos los targets estén completamente migrados. Cuando termines, recomendamos actualizar tus pipelines de CI y CD para compilar y probar el proyecto usando tuist generate seguido de xcodebuild build y tuist test.

Solución de problemas#

Errores de compilación por archivos faltantes.#

Si los archivos asociados a los targets de tu proyecto de Xcode no estaban todos contenidos en un directorio del sistema de archivos que representara el target, podrías terminar con un proyecto que no compila. Asegúrate de que la lista de archivos tras generar el proyecto con Tuist coincida con la lista de archivos del proyecto de Xcode y aprovecha para alinear la estructura de archivos con la estructura de targets.