Add support for customizing profile and analyze action

This commit is contained in:
Zhuhao Wang 2020-02-06 15:33:12 +08:00 committed by zhuhaow
parent bf14dd71fc
commit cb55e98544
No known key found for this signature in database
GPG Key ID: F830A3A97689289E
14 changed files with 243 additions and 16 deletions

View File

@ -0,0 +1,13 @@
import Foundation
public struct AnalyzeAction: Equatable, Codable {
public let configurationName: String
public init(configurationName: String) {
self.configurationName = configurationName
}
public init(config: PresetBuildConfiguration = .release) {
self.init(configurationName: config.name)
}
}

View File

@ -0,0 +1,23 @@
import Foundation
public struct ProfileAction: Equatable, Codable {
public let configurationName: String
public let executable: TargetReference?
public let arguments: Arguments?
public init(configurationName: String,
executable: TargetReference? = nil,
arguments: Arguments? = nil) {
self.configurationName = configurationName
self.executable = executable
self.arguments = arguments
}
public init(config: PresetBuildConfiguration = .release,
executable: TargetReference? = nil,
arguments: Arguments? = nil) {
self.init(configurationName: config.name,
executable: executable,
arguments: arguments)
}
}

View File

@ -9,18 +9,24 @@ public struct Scheme: Equatable, Codable {
public let testAction: TestAction?
public let runAction: RunAction?
public let archiveAction: ArchiveAction?
public let profileAction: ProfileAction?
public let analyzeAction: AnalyzeAction?
public init(name: String,
shared: Bool = true,
buildAction: BuildAction? = nil,
testAction: TestAction? = nil,
runAction: RunAction? = nil,
archiveAction: ArchiveAction? = nil) {
archiveAction: ArchiveAction? = nil,
profileAction: ProfileAction? = nil,
analyzeAction: AnalyzeAction? = nil) {
self.name = name
self.shared = shared
self.buildAction = buildAction
self.testAction = testAction
self.runAction = runAction
self.archiveAction = archiveAction
self.profileAction = profileAction
self.analyzeAction = analyzeAction
}
}

View File

@ -0,0 +1,13 @@
import Foundation
public struct AnalyzeAction: Equatable {
// MARK: - Attributes
public let configurationName: String
// MARK: - Init
public init(configurationName: String) {
self.configurationName = configurationName
}
}

View File

@ -0,0 +1,19 @@
import Foundation
public struct ProfileAction: Equatable {
// MARK: - Attributes
public let configurationName: String
public let executable: TargetReference?
public let arguments: Arguments?
// MARK: - Init
public init(configurationName: String,
executable: TargetReference? = nil,
arguments: Arguments? = nil) {
self.configurationName = configurationName
self.executable = executable
self.arguments = arguments
}
}

View File

@ -10,6 +10,8 @@ public struct Scheme: Equatable {
public let testAction: TestAction?
public let runAction: RunAction?
public let archiveAction: ArchiveAction?
public let profileAction: ProfileAction?
public let analyzeAction: AnalyzeAction?
// MARK: - Init
@ -18,13 +20,17 @@ public struct Scheme: Equatable {
buildAction: BuildAction? = nil,
testAction: TestAction? = nil,
runAction: RunAction? = nil,
archiveAction: ArchiveAction? = nil) {
archiveAction: ArchiveAction? = nil,
profileAction: ProfileAction? = nil,
analyzeAction: AnalyzeAction? = nil) {
self.name = name
self.shared = shared
self.buildAction = buildAction
self.testAction = testAction
self.runAction = runAction
self.archiveAction = archiveAction
self.profileAction = profileAction
self.analyzeAction = analyzeAction
}
public func targetDependencies() -> [TargetReference] {
@ -39,6 +45,7 @@ public struct Scheme: Equatable {
runAction?.executable.map { [$0] },
archiveAction?.preActions.compactMap(\.target),
archiveAction?.postActions.compactMap(\.target),
profileAction?.executable.map { [$0] }
]
let targets = targetSources.compactMap { $0 }.flatMap { $0 }.uniqued()

View File

@ -0,0 +1,9 @@
import Basic
import Foundation
@testable import TuistCore
public extension AnalyzeAction {
static func test(configurationName: String = "Beta Release") -> AnalyzeAction {
AnalyzeAction(configurationName: configurationName)
}
}

View File

@ -0,0 +1,13 @@
import Basic
import Foundation
@testable import TuistCore
public extension ProfileAction {
static func test(configurationName: String = "Beta Release",
executable: TargetReference? = TargetReference(projectPath: "/Project", name: "App"),
arguments: Arguments? = Arguments.test()) -> ProfileAction {
ProfileAction(configurationName: configurationName,
executable: executable,
arguments: arguments)
}
}

View File

@ -8,12 +8,16 @@ public extension Scheme {
buildAction: BuildAction? = BuildAction.test(),
testAction: TestAction? = TestAction.test(),
runAction: RunAction? = RunAction.test(),
archiveAction: ArchiveAction? = ArchiveAction.test()) -> Scheme {
archiveAction: ArchiveAction? = ArchiveAction.test(),
profileAction: ProfileAction? = ProfileAction.test(),
analyzeAction: AnalyzeAction? = AnalyzeAction.test()) -> Scheme {
Scheme(name: name,
shared: shared,
buildAction: buildAction,
testAction: testAction,
runAction: runAction,
archiveAction: archiveAction)
archiveAction: archiveAction,
profileAction: profileAction,
analyzeAction: analyzeAction)
}
}

View File

@ -382,9 +382,23 @@ final class SchemesGenerator: SchemesGenerating {
rootPath: AbsolutePath,
generatedProjects: [AbsolutePath: GeneratedProject]) throws -> XCScheme.ProfileAction? {
guard var target = try defaultTargetReference(scheme: scheme) else { return nil }
if let executable = scheme.runAction?.executable {
var commandlineArguments: XCScheme.CommandLineArguments?
var environments: [XCScheme.EnvironmentVariable]?
if let action = scheme.profileAction, let executable = action.executable {
target = executable
if let arguments = action.arguments {
commandlineArguments = XCScheme.CommandLineArguments(arguments: commandlineArgruments(arguments.launch))
environments = environmentVariables(arguments.environment)
}
} else if let action = scheme.runAction, let executable = action.executable {
target = executable
if let arguments = action.arguments {
commandlineArguments = XCScheme.CommandLineArguments(arguments: commandlineArgruments(arguments.launch))
environments = environmentVariables(arguments.environment)
}
}
guard let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
guard let buildableReference = try createBuildableReference(targetReference: target,
graph: graph,
@ -400,10 +414,12 @@ final class SchemesGenerator: SchemesGenerating {
macroExpansion = buildableReference
}
let buildConfiguration = defaultReleaseBuildConfigurationName(in: targetNode.project)
let buildConfiguration = scheme.profileAction?.configurationName ?? defaultReleaseBuildConfigurationName(in: targetNode.project)
return XCScheme.ProfileAction(buildableProductRunnable: buildableProductRunnable,
buildConfiguration: buildConfiguration,
macroExpansion: macroExpansion)
macroExpansion: macroExpansion,
commandlineArguments: commandlineArguments,
environmentVariables: environments)
}
/// Returns the scheme analyze action.
@ -421,7 +437,7 @@ final class SchemesGenerator: SchemesGenerating {
guard let target = try defaultTargetReference(scheme: scheme),
let targetNode = try graph.target(path: target.projectPath, name: target.name) else { return nil }
let buildConfiguration = defaultDebugBuildConfigurationName(in: targetNode.project)
let buildConfiguration = scheme.analyzeAction?.configurationName ?? defaultDebugBuildConfigurationName(in: targetNode.project)
return XCScheme.AnalyzeAction(buildConfiguration: buildConfiguration)
}

View File

@ -519,8 +519,9 @@ final class SchemesGeneratorTests: XCTestCase {
let buildAction = BuildAction.test(targets: [appTargetReference])
let testAction = TestAction.test(targets: [TestableTarget(target: appTargetReference)])
let runAction = RunAction.test(configurationName: "Release", executable: appTargetReference, arguments: nil)
let profileAction = ProfileAction.test(configurationName: "Beta Release", executable: appTargetReference, arguments: nil)
let scheme = Scheme.test(name: "App", buildAction: buildAction, testAction: testAction, runAction: runAction)
let scheme = Scheme.test(name: "App", buildAction: buildAction, testAction: testAction, runAction: runAction, profileAction: profileAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
@ -541,7 +542,7 @@ final class SchemesGeneratorTests: XCTestCase {
XCTAssertEqual(buildable.blueprintName, target.name)
XCTAssertEqual(buildable.buildableIdentifier, "primary")
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.buildConfiguration, "Beta Release")
XCTAssertEqual(result.preActions, [])
XCTAssertEqual(result.postActions, [])
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
@ -562,7 +563,8 @@ final class SchemesGeneratorTests: XCTestCase {
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "Library")])
let testAction = TestAction.test(targets: [TestableTarget(target: TargetReference(projectPath: projectPath, name: "Library"))])
let scheme = Scheme.test(name: "Library", buildAction: buildAction, testAction: testAction, runAction: nil)
let profileAction = ProfileAction.test(configurationName: "Beta Release", executable: nil)
let scheme = Scheme.test(name: "Library", buildAction: buildAction, testAction: testAction, runAction: nil, profileAction: profileAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
@ -578,7 +580,7 @@ final class SchemesGeneratorTests: XCTestCase {
let buildable = result.buildableProductRunnable?.buildableReference
XCTAssertNil(buildable)
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.buildConfiguration, "Beta Release")
XCTAssertEqual(result.preActions, [])
XCTAssertEqual(result.postActions, [])
XCTAssertEqual(result.shouldUseLaunchSchemeArgsEnv, true)
@ -590,19 +592,20 @@ final class SchemesGeneratorTests: XCTestCase {
XCTAssertNil(result.environmentVariables)
XCTAssertEqual(result.enableTestabilityWhenProfilingTests, true)
XCTAssertEqual(result.buildConfiguration, "Release")
XCTAssertEqual(result.macroExpansion?.referencedContainer, "container:Project.xcodeproj")
XCTAssertEqual(result.macroExpansion?.buildableName, "libLibrary.dylib")
XCTAssertEqual(result.macroExpansion?.blueprintName, "Library")
XCTAssertEqual(result.macroExpansion?.buildableIdentifier, "primary")
}
// MARK: - Analyze Action Tests
func test_schemeAnalyzeAction() throws {
// Given
let projectPath = AbsolutePath("/Project")
let target = Target.test(name: "App", platform: .iOS, product: .app)
let buildAction = BuildAction.test(targets: [TargetReference(projectPath: projectPath, name: "App")])
let scheme = Scheme.test(buildAction: buildAction)
let analyzeAction = AnalyzeAction.test(configurationName: "Beta Release")
let scheme = Scheme.test(buildAction: buildAction, analyzeAction: analyzeAction)
let project = Project.test(path: projectPath, targets: [target])
let graph = Graph.create(dependencies: [(project: project, target: target, dependencies: [])])
@ -615,7 +618,7 @@ final class SchemesGeneratorTests: XCTestCase {
// Then
let result = try XCTUnwrap(got)
XCTAssertEqual(result.buildConfiguration, "Debug")
XCTAssertEqual(result.buildConfiguration, "Beta Release")
}
func test_defaultSchemeArchiveAction() {

View File

@ -182,6 +182,7 @@ Scenario: The project is an iOS application with multiple configurations (ios_ap
Then the scheme Framework2 has a build setting CUSTOM_FLAG with value "Target.Beta" for the configuration Beta
Then the scheme Framework2 has a build setting CUSTOM_FLAG with value "Release" for the configuration Release
Then I should be able to archive for iOS the scheme App
Then I should be able to analyze for iOS the scheme App
Scenario: The project is an iOS application with CocoaPods dependencies (ios_app_with_pods)
Given that tuist is available

View File

@ -14,7 +14,9 @@ let betaScheme = Scheme(name: "App-Beta",
shared: true,
buildAction: BuildAction(targets: ["App"]),
runAction: RunAction(configurationName: "Beta", executable: "App"),
archiveAction: ArchiveAction(configurationName: "Beta"))
archiveAction: ArchiveAction(configurationName: "Beta"),
profileAction: ProfileAction(configurationName: "Release", executable: "App"),
analyzeAction: AnalyzeAction(configurationName: "Debug"))
let project = Project(name: "MainApp",
settings: settings,

View File

@ -679,6 +679,22 @@ typeLink: '#archive-action',
optional: true,
default: 'nil',
},
{
name: 'Profile action',
description: 'Action that profiles the project.',
type: 'ProfileAction',
typeLink: '#profile-action',
optional: true,
default: 'nil',
},
{
name: 'Analyze action',
description: 'Action that analyze the project.',
type: 'AnalyzeAction',
typeLink: '#analyze-action',
optional: true,
default: 'nil',
},
]}
/>
@ -995,6 +1011,88 @@ Arguments contain commandline arguments passed on launch and Environment variabl
]}
/>
### Profile action
It represents the scheme action that profiles the built products on the supported platforms:
<PropertiesTable
properties={[
{
name: 'Config',
description:
'Indicates the build configuration the product should be profiled with.',
type: 'PresetBuildConfiguration',
typeLink: '#preset-build-configuration',
optional: true,
default: '.release',
},
{
name: 'Executable',
description: 'The name of the executable or target to profile.',
type: 'TargetReference',
optional: true,
default: 'nil',
},
{
name: 'Arguments',
description:
'Commandline arguments passed on launch and environment variables.',
type: 'Arguments',
typeLink: '#arguments',
optional: true,
default: 'nil',
},
]}
/>
Alternatively, when leveraging custom configurations, the configuration name can be explicitly specified:
<PropertiesTable
properties={[
{
name: 'Configuration Name',
description:
'Indicates the build configuration the product should be profiled with.',
type: 'String',
optional: false,
default: '',
},
]}
/>
### Analyze action
It represents the scheme action that analyzes the built products:
<PropertiesTable
properties={[
{
name: 'Config',
description:
'Indicates the build configuration the product should be analyzed with.',
type: 'PresetBuildConfiguration',
typeLink: '#preset-build-configuration',
optional: true,
default: '.debug',
}
]}
/>
Alternatively, when leveraging custom configurations, the configuration name can be explicitly specified:
<PropertiesTable
properties={[
{
name: 'Configuration Name',
description:
'Indicates the build configuration the product should be analyzed with.',
type: 'String',
optional: false,
default: '',
},
]}
/>
## Settings
A `Settings` object contains an optional dictionary with build settings and relative path to an `.xcconfig` file. It is initialized with the following attributes: