Bugfix/templates (#1600)
* Use name of template instead of Template.swift. * Rename Template.swift in rest of documetnation. * Fix tests. * Add documentation for fileName method. * Update changelog. * Reformat code. * Fix CachedManifestLoaderTests.
This commit is contained in:
parent
3bd6a4950a
commit
fce1fc2b9a
|
@ -6,6 +6,7 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
### Fixed
|
||||
|
||||
- Fix name collision when having multiple templates [#1600](https://github.com/tuist/tuist/pull/1600) by [@fortmarek](https://github.com/fortmarek)
|
||||
- Allow to cache and warm static frameworks too (only dynamic frameworks were cached before) [#1590](https://github.com/tuist/tuist/pull/1590) by [@RomainBoulay](https://github.com/RomainBoulay)
|
||||
- Add support for `.xctest` dependency for tvOS targets [#1597](https://github.com/tuist/tuist/pull/1597) by [@kwridan](https://github.com/kwridan).
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ public struct Template: Codable, Equatable {
|
|||
|
||||
/// Enum containing information about how to generate file
|
||||
public enum Contents: Codable, Equatable {
|
||||
/// String Contents is defined in `Template.swift` and contains a simple `String`
|
||||
/// String Contents is defined in `name_of_template.swift` and contains a simple `String`
|
||||
/// Can not contain any additional logic apart from plain `String` from `arguments`
|
||||
case string(String)
|
||||
/// File content is defined in a different file from `Template.swift`
|
||||
/// File content is defined in a different file from `name_of_template.swift`
|
||||
/// Can contain additional logic and anything that is defined in `ProjectDescriptionHelpers`
|
||||
case file(Path)
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ public class CachedManifestLoader: ManifestLoading {
|
|||
}
|
||||
|
||||
private func findManifestPath(for manifest: Manifest, at path: AbsolutePath) -> AbsolutePath? {
|
||||
let manifestFileNames = [manifest.fileName, manifest.deprecatedFileName]
|
||||
let manifestFileNames = [manifest.fileName(path), manifest.deprecatedFileName]
|
||||
return manifestFileNames
|
||||
.compactMap { $0 }
|
||||
.map { path.appending(component: $0) }
|
||||
|
|
|
@ -48,7 +48,7 @@ extension GeneratorModelLoader: GeneratorModelLoading {
|
|||
public func loadConfig(at path: AbsolutePath) throws -> TuistCore.Config {
|
||||
// If the Config.swift file exists in the root Tuist/ directory, we load it from there
|
||||
if let rootDirectoryPath = rootDirectoryLocator.locate(from: path) {
|
||||
let configPath = rootDirectoryPath.appending(RelativePath("\(Constants.tuistDirectoryName)/\(Manifest.config.fileName)"))
|
||||
let configPath = rootDirectoryPath.appending(RelativePath("\(Constants.tuistDirectoryName)/\(Manifest.config.fileName(path))"))
|
||||
|
||||
if FileHandler.shared.exists(configPath) {
|
||||
let manifest = try manifestLoader.loadConfig(at: configPath.parentDirectory)
|
||||
|
@ -58,7 +58,7 @@ extension GeneratorModelLoader: GeneratorModelLoading {
|
|||
|
||||
// We first try to load the deprecated file. If it doesn't exist, we load the new file name.
|
||||
let fileNames = [Manifest.config]
|
||||
.flatMap { [$0.deprecatedFileName, $0.fileName] }
|
||||
.flatMap { [$0.deprecatedFileName, $0.fileName(path)] }
|
||||
.compactMap { $0 }
|
||||
|
||||
for fileName in fileNames {
|
||||
|
|
|
@ -22,9 +22,9 @@ public enum ManifestLoaderError: FatalError, Equatable {
|
|||
case let .unexpectedOutput(path):
|
||||
return "Unexpected output trying to parse the manifest at path \(path.pathString)"
|
||||
case let .manifestNotFound(manifest, path):
|
||||
return "\(manifest?.fileName ?? "Manifest") not found at path \(path.pathString)"
|
||||
return "\(manifest?.fileName(path) ?? "Manifest") not found at path \(path.pathString)"
|
||||
case let .manifestCachingFailed(manifest, path):
|
||||
return "Could not cache \(manifest?.fileName ?? "Manifest") at path \(path.pathString)"
|
||||
return "Could not cache \(manifest?.fileName(path) ?? "Manifest") at path \(path.pathString)"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,9 @@ public protocol ManifestLoading {
|
|||
/// - Parameter path: Path to the directory that contains the Setup.swift.
|
||||
func loadSetup(at path: AbsolutePath) throws -> [Upping]
|
||||
|
||||
/// Loads the Template.swift in the given directory.
|
||||
/// Loads the name_of_template.swift in the given directory.
|
||||
/// - Parameters:
|
||||
/// - path: Path to the directory that contains the Template.swift
|
||||
/// - path: Path to the directory that contains the name_of_template.swift
|
||||
func loadTemplate(at path: AbsolutePath) throws -> ProjectDescription.Template
|
||||
|
||||
/// List all the manifests in the given directory.
|
||||
|
@ -137,7 +137,7 @@ public class ManifestLoader: ManifestLoading {
|
|||
}
|
||||
|
||||
public func loadSetup(at path: AbsolutePath) throws -> [Upping] {
|
||||
let setupPath = path.appending(component: Manifest.setup.fileName)
|
||||
let setupPath = path.appending(component: Manifest.setup.fileName(path))
|
||||
guard FileHandler.shared.exists(setupPath) else {
|
||||
throw ManifestLoaderError.manifestNotFound(.setup, path)
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class ManifestLoader: ManifestLoading {
|
|||
// MARK: - Private
|
||||
|
||||
private func loadManifest<T: Decodable>(_ manifest: Manifest, at path: AbsolutePath) throws -> T {
|
||||
var fileNames = [manifest.fileName]
|
||||
var fileNames = [manifest.fileName(path)]
|
||||
if let deprecatedFileName = manifest.deprecatedFileName {
|
||||
fileNames.insert(deprecatedFileName, at: 0)
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class SetupLoader: SetupLoading {
|
|||
/// or if there isn't a `Setup.swift` file within the project path.
|
||||
public func meet(at path: AbsolutePath) throws {
|
||||
let path = try lookupManifest(from: path)
|
||||
logger.info("Setting up the environment defined in \(path.appending(component: Manifest.setup.fileName).pathString)")
|
||||
logger.info("Setting up the environment defined in \(path.appending(component: Manifest.setup.fileName(path)).pathString)")
|
||||
let setup = try manifestLoader.loadSetup(at: path)
|
||||
try setup.map { command in upLinter.lint(up: command) }
|
||||
.flatMap { $0 }
|
||||
|
@ -78,7 +78,7 @@ public class SetupLoader: SetupLoading {
|
|||
/// It traverses up the directory hierarchy until it finds a Setup.swift file.
|
||||
/// - Parameter path: Path from where to do the lookup.
|
||||
private func lookupManifest(from path: AbsolutePath) throws -> AbsolutePath {
|
||||
let manfiestPath = path.appending(component: Manifest.setup.fileName)
|
||||
let manfiestPath = path.appending(component: Manifest.setup.fileName(path))
|
||||
if FileHandler.shared.exists(manfiestPath) {
|
||||
return path
|
||||
} else if path != .root {
|
||||
|
|
|
@ -7,7 +7,7 @@ import TuistSupport
|
|||
public protocol TemplateLoading {
|
||||
/// Load `TuistScaffold.Template` at given `path`
|
||||
/// - Parameters:
|
||||
/// - path: Path of template manifest file `Template.swift`
|
||||
/// - path: Path of template manifest file `name_of_template.swift`
|
||||
/// - Returns: Loaded `TuistScaffold.Template`
|
||||
func loadTemplate(at path: AbsolutePath) throws -> TuistCore.Template
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Foundation
|
||||
import TSCBasic
|
||||
|
||||
public enum Manifest: CaseIterable {
|
||||
case project
|
||||
|
@ -13,12 +14,17 @@ public enum Manifest: CaseIterable {
|
|||
switch self {
|
||||
case .config:
|
||||
return "TuistConfig.swift"
|
||||
case .template:
|
||||
return "Template.swift"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var fileName: String {
|
||||
/// - Parameters:
|
||||
/// - path: Path to the folder that contains the manifest
|
||||
/// - Returns: File name of the `Manifest`
|
||||
public func fileName(_ path: AbsolutePath) -> String {
|
||||
switch self {
|
||||
case .project:
|
||||
return "Project.swift"
|
||||
|
@ -29,7 +35,7 @@ public enum Manifest: CaseIterable {
|
|||
case .setup:
|
||||
return "Setup.swift"
|
||||
case .template:
|
||||
return "Template.swift"
|
||||
return "\(path.basenameWithoutExt).swift"
|
||||
case .galaxy:
|
||||
return "Galaxy.swift"
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ public final class ManifestFilesLocator: ManifestFilesLocating {
|
|||
|
||||
public func locate(at: AbsolutePath) -> [(Manifest, AbsolutePath)] {
|
||||
Manifest.allCases.compactMap { manifest in
|
||||
let path = at.appending(component: manifest.fileName)
|
||||
let path = at.appending(component: manifest.fileName(at))
|
||||
if FileHandler.shared.exists(path) { return (manifest, path) }
|
||||
return nil
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ public final class ManifestFilesLocator: ManifestFilesLocating {
|
|||
|
||||
public func locateAll(at: AbsolutePath) -> [(Manifest, AbsolutePath)] {
|
||||
guard let rootPath = rootDirectoryLocator.locate(from: at) else { return locate(at: at) }
|
||||
let projectsPaths = FileHandler.shared.glob(rootPath, glob: "**/\(Manifest.project.fileName)").map { (Manifest.project, $0) }
|
||||
let workspacesPaths = FileHandler.shared.glob(rootPath, glob: "**/\(Manifest.workspace.fileName)").map { (Manifest.workspace, $0) }
|
||||
let projectsPaths = FileHandler.shared.glob(rootPath, glob: "**/\(Manifest.project.fileName(at))").map { (Manifest.project, $0) }
|
||||
let workspacesPaths = FileHandler.shared.glob(rootPath, glob: "**/\(Manifest.workspace.fileName(at))").map { (Manifest.workspace, $0) }
|
||||
return projectsPaths + workspacesPaths
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ let template = Template(
|
|||
templatePath: templatePath("Config.stencil")),
|
||||
.file(path: ".gitignore",
|
||||
templatePath: templatePath("Gitignore.stencil")),
|
||||
.file(path: "Tuist/Templates/framework/Template.swift",
|
||||
.file(path: "Tuist/Templates/framework/framework.swift",
|
||||
templatePath: templatePath("ExampleTemplate.stencil")),
|
||||
.file(path: "Tuist/Templates/framework/project.stencil",
|
||||
templatePath: templatePath("ExampleProject")),
|
||||
|
|
|
@ -27,7 +27,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
let config = Config(generationOptions: [])
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.config.fileName)
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.config.fileName(temporaryPath))
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
@ -44,7 +44,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
let project = Project(name: "tuist")
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.project.fileName)
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.project.fileName(temporaryPath))
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
@ -64,7 +64,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
let workspace = Workspace(name: "tuist", projects: [])
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.workspace.fileName)
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.workspace.fileName(temporaryPath))
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
@ -86,7 +86,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
])
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.setup.fileName)
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.setup.fileName(temporaryPath))
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
@ -102,7 +102,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
XCTAssertEqual(customUp?.isMet, ["c"])
|
||||
}
|
||||
|
||||
func test_loadTemplate() throws {
|
||||
func test_loadDeprecatedTemplate() throws {
|
||||
// Given
|
||||
let temporaryPath = try self.temporaryPath()
|
||||
let content = """
|
||||
|
@ -125,6 +125,30 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
XCTAssertEqual(got.description, "Template description")
|
||||
}
|
||||
|
||||
func test_loadTemplate() throws {
|
||||
// Given
|
||||
let temporaryPath = try self.temporaryPath().appending(component: "folder")
|
||||
try fileHandler.createFolder(temporaryPath)
|
||||
let content = """
|
||||
import ProjectDescription
|
||||
|
||||
let template = Template(
|
||||
description: "Template description"
|
||||
)
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: "folder.swift")
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
||||
// When
|
||||
let got = try subject.loadTemplate(at: temporaryPath)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(got.description, "Template description")
|
||||
}
|
||||
|
||||
func test_load_invalidFormat() throws {
|
||||
// Given
|
||||
let temporaryPath = try self.temporaryPath()
|
||||
|
@ -133,7 +157,7 @@ final class ManifestLoaderTests: TuistTestCase {
|
|||
let project
|
||||
"""
|
||||
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.project.fileName)
|
||||
let manifestPath = temporaryPath.appending(component: Manifest.project.fileName(temporaryPath))
|
||||
try content.write(to: manifestPath.url,
|
||||
atomically: true,
|
||||
encoding: .utf8)
|
||||
|
|
|
@ -245,7 +245,7 @@ final class CachedManifestLoaderTests: TuistUnitTestCase {
|
|||
private func stub(manifest: Project,
|
||||
at path: AbsolutePath) throws
|
||||
{
|
||||
let manifestPath = path.appending(component: Manifest.project.fileName)
|
||||
let manifestPath = path.appending(component: Manifest.project.fileName(path))
|
||||
try fileHandler.touch(manifestPath)
|
||||
let manifestData = try JSONEncoder().encode(manifest)
|
||||
try fileHandler.write(String(data: manifestData, encoding: .utf8)!, path: manifestPath, atomically: true)
|
||||
|
@ -255,7 +255,7 @@ final class CachedManifestLoaderTests: TuistUnitTestCase {
|
|||
private func stub(deprecatedManifest manifest: Config,
|
||||
at path: AbsolutePath) throws
|
||||
{
|
||||
let manifestPath = path.appending(component: Manifest.config.deprecatedFileName ?? Manifest.config.fileName)
|
||||
let manifestPath = path.appending(component: Manifest.config.deprecatedFileName ?? Manifest.config.fileName(path))
|
||||
try fileHandler.touch(manifestPath)
|
||||
let manifestData = try JSONEncoder().encode(manifest)
|
||||
try fileHandler.write(String(data: manifestData, encoding: .utf8)!, path: manifestPath, atomically: true)
|
||||
|
|
|
@ -255,7 +255,7 @@ final class RecursiveManifestLoaderTests: TuistUnitTestCase {
|
|||
{
|
||||
let manifestPath = path
|
||||
.appending(relativePath)
|
||||
.appending(component: Manifest.project.fileName)
|
||||
.appending(component: Manifest.project.fileName(path.appending(relativePath)))
|
||||
try fileHandler.touch(manifestPath)
|
||||
projectManifests[manifestPath.parentDirectory] = manifest
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ final class RecursiveManifestLoaderTests: TuistUnitTestCase {
|
|||
{
|
||||
let manifestPath = path
|
||||
.appending(relativePath)
|
||||
.appending(component: Manifest.workspace.fileName)
|
||||
.appending(component: Manifest.workspace.fileName(path.appending(relativePath)))
|
||||
try fileHandler.touch(manifestPath)
|
||||
workspaceManifests[manifestPath.parentDirectory] = manifest
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ final class SetupLoaderTests: TuistUnitTestCase {
|
|||
func test_meet_when_no_actions() throws {
|
||||
// given
|
||||
let projectPath = try temporaryPath()
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName))
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName(projectPath)))
|
||||
var receivedPaths = [String]()
|
||||
manifestLoader.loadSetupStub = { gotPath in
|
||||
receivedPaths.append(gotPath.pathString)
|
||||
|
@ -56,7 +56,7 @@ final class SetupLoaderTests: TuistUnitTestCase {
|
|||
func test_meet_when_actions_provided() throws {
|
||||
// given
|
||||
let projectPath = try temporaryPath()
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName))
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName(projectPath)))
|
||||
|
||||
let mockUp1 = MockUp(name: "1")
|
||||
mockUp1.isMetStub = { _ in true }
|
||||
|
@ -82,7 +82,7 @@ final class SetupLoaderTests: TuistUnitTestCase {
|
|||
// given
|
||||
let temporaryPath = try self.temporaryPath()
|
||||
let projectPath = temporaryPath.appending(component: "Project")
|
||||
try FileHandler.shared.touch(temporaryPath.appending(component: Manifest.setup.fileName))
|
||||
try FileHandler.shared.touch(temporaryPath.appending(component: Manifest.setup.fileName(projectPath)))
|
||||
|
||||
let mockUp1 = MockUp(name: "1")
|
||||
mockUp1.isMetStub = { _ in true }
|
||||
|
@ -107,7 +107,7 @@ final class SetupLoaderTests: TuistUnitTestCase {
|
|||
func test_meet_when_loadSetup_throws() throws {
|
||||
// given
|
||||
let projectPath = try temporaryPath()
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName))
|
||||
try FileHandler.shared.touch(projectPath.appending(component: Manifest.setup.fileName(projectPath)))
|
||||
manifestLoader.loadSetupStub = { _ in throw ManifestLoaderError.manifestNotFound(.setup, projectPath) }
|
||||
|
||||
// when / then
|
||||
|
|
|
@ -5,12 +5,14 @@ import XCTest
|
|||
@testable import TuistSupportTesting
|
||||
|
||||
final class ManifestTests: TuistUnitTestCase {
|
||||
func test_fileName() {
|
||||
XCTAssertEqual(Manifest.project.fileName, "Project.swift")
|
||||
XCTAssertEqual(Manifest.workspace.fileName, "Workspace.swift")
|
||||
XCTAssertEqual(Manifest.config.fileName, "Config.swift")
|
||||
XCTAssertEqual(Manifest.setup.fileName, "Setup.swift")
|
||||
XCTAssertEqual(Manifest.galaxy.fileName, "Galaxy.swift")
|
||||
func test_fileName() throws {
|
||||
let temporaryPath = try self.temporaryPath().appending(component: "folder")
|
||||
XCTAssertEqual(Manifest.project.fileName(temporaryPath), "Project.swift")
|
||||
XCTAssertEqual(Manifest.workspace.fileName(temporaryPath), "Workspace.swift")
|
||||
XCTAssertEqual(Manifest.config.fileName(temporaryPath), "Config.swift")
|
||||
XCTAssertEqual(Manifest.setup.fileName(temporaryPath), "Setup.swift")
|
||||
XCTAssertEqual(Manifest.galaxy.fileName(temporaryPath), "Galaxy.swift")
|
||||
XCTAssertEqual(Manifest.template.fileName(temporaryPath), "folder.swift")
|
||||
}
|
||||
|
||||
func test_deprecatedFileName() {
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
Feature: Scaffold a project using Tuist
|
||||
|
||||
Scenario: The project is an application with templates (ios_app_with_templates)
|
||||
Given that tuist is available
|
||||
Given that tuist is available
|
||||
And I have a working directory
|
||||
Then I copy the fixture ios_app_with_templates into the working directory
|
||||
Then tuist scaffolds a custom template to TemplateProject named TemplateProject
|
||||
Then content of a file named TemplateProject/custom.swift in a directory TemplateProject should be equal to // this is test TemplateProject content
|
||||
Then content of a file named TemplateProject/generated.swift in a directory TemplateProject should be equal to // Generated file with platform: ios and name: TemplateProject
|
||||
|
||||
Then content of a file named TemplateProject/generated.swift in a directory TemplateProject should be equal to:
|
||||
"""
|
||||
// Generated file with platform: ios and name: TemplateProject
|
||||
|
||||
"""
|
||||
# Uses new naming where name of template file is no longer `Template.swift` but `name_of_template.swift`
|
||||
Then tuist scaffolds a custom_two template to TemplateProject named TemplateProject
|
||||
Then content of a file named TemplateProject/custom.swift in a directory TemplateProject should be equal to // this is test TemplateProject content
|
||||
Then content of a file named TemplateProject/generated.swift in a directory TemplateProject should be equal to:
|
||||
"""
|
||||
// Generated file with platform: ios and name: TemplateProject
|
||||
|
||||
"""
|
||||
Scenario: The project is a just initialized project
|
||||
Given that tuist is available
|
||||
And I have a working directory
|
||||
|
@ -15,4 +26,4 @@ Feature: Scaffold a project using Tuist
|
|||
And tuist scaffolds a framework template to Projects/ named MyFeature
|
||||
When tuist generates the project at Projects/MyFeature
|
||||
Then I should be able to build for iOS the scheme MyFeature
|
||||
Then I should be able to test for iOS the scheme MyFeature
|
||||
Then I should be able to test for iOS the scheme MyFeature
|
||||
|
|
|
@ -7,3 +7,7 @@ end
|
|||
Then(/content of a file named (.+) in a directory (.+) should be equal to (.+)/) do |file, dir, content|
|
||||
assert_equal File.read(File.join(@dir, dir, file)), content
|
||||
end
|
||||
|
||||
Then(/content of a file named (.+) in a directory (.+) should be equal to:$/) do |file, dir, content|
|
||||
assert_equal File.read(File.join(@dir, dir, file)), content
|
||||
end
|
||||
|
|
|
@ -2,23 +2,28 @@ import ProjectDescription
|
|||
|
||||
let project = Project(name: "App",
|
||||
targets: [
|
||||
Target(name: "App",
|
||||
platform: .iOS,
|
||||
product: .app,
|
||||
bundleId: "io.tuist.App",
|
||||
infoPlist: "Support/Info.plist",
|
||||
sources: ["Sources/**"],
|
||||
resources: [
|
||||
/* Path to resouces can be defined here */
|
||||
// "Resources/**"
|
||||
],
|
||||
Target(name: "AppTests",
|
||||
platform: .iOS,
|
||||
product: .unitTests,
|
||||
bundleId: "io.tuist.AppTests",
|
||||
infoPlist: "Support/Tests.plist",
|
||||
sources: "Tests/**",
|
||||
dependencies: [
|
||||
.target(name: "App")
|
||||
])
|
||||
])
|
||||
Target(
|
||||
name: "App",
|
||||
platform: .iOS,
|
||||
product: .app,
|
||||
bundleId: "io.tuist.App",
|
||||
infoPlist: "Support/Info.plist",
|
||||
sources: ["Sources/**"],
|
||||
resources: [
|
||||
/* Path to resouces can be defined here */
|
||||
// "Resources/**"
|
||||
]
|
||||
),
|
||||
Target(
|
||||
name: "AppTests",
|
||||
platform: .iOS,
|
||||
product: .unitTests,
|
||||
bundleId: "io.tuist.AppTests",
|
||||
infoPlist: "Support/Tests.plist",
|
||||
sources: "Tests/**",
|
||||
dependencies: [
|
||||
.target(name: "App")
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
|
|
@ -1 +1 @@
|
|||
// Generated file with platform: {{ platform }} and name: {{ name }}
|
||||
// Generated file with platform: {{ platform }} and name: {{ name }}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import ProjectDescription
|
||||
|
||||
let nameAttributeTwo: Template.Attribute = .required("name")
|
||||
let platformAttributeTwo: Template.Attribute = .optional("platform", default: "ios")
|
||||
|
||||
let testContentsTwo = """
|
||||
// this is test \(nameAttributeTwo) content
|
||||
"""
|
||||
|
||||
let templateTwo = Template(
|
||||
description: "Custom template",
|
||||
attributes: [
|
||||
nameAttributeTwo,
|
||||
platformAttributeTwo
|
||||
],
|
||||
files: [
|
||||
.string(path: "\(nameAttributeTwo)/custom.swift", contents: testContentsTwo),
|
||||
.file(path: "\(nameAttributeTwo)/generated.swift", templatePath: "platform_two.stencil"),
|
||||
]
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
// Generated file with platform: {{ platform }} and name: {{ name }}
|
|
@ -15,7 +15,7 @@ Tuist is not opinionated about the content of your templates, and what you use t
|
|||
|
||||
## Defining a template
|
||||
|
||||
To define templates, you can run `tuist edit` and then create a directory under `Tuist/Templates` that represents your template. Templates need a manifest file, `Template.swift` that describes the template:
|
||||
To define templates, you can run `tuist edit` and then create a directory called `name_of_template` under `Tuist/Templates` that represents your template. Templates need a manifest file, `name_of_template.swift` that describes the template. So if you are creating a template called `framework`, you should create a new directory `framework` at `Tuist/Templates` with a manifest file called `framework.swift` that could look like this:
|
||||
|
||||
```swift
|
||||
import ProjectDescription
|
||||
|
|
Loading…
Reference in New Issue