Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Archive Action on Scheme #529

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 28 additions & 1 deletion Sources/ProjectDescription/Scheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ public struct Scheme: Equatable, Codable {
public let buildAction: BuildAction?
public let testAction: TestAction?
public let runAction: RunAction?
public let archiveAction: ArchiveAction?

public init(name: String,
shared: Bool = true,
buildAction: BuildAction? = nil,
testAction: TestAction? = nil,
runAction: RunAction? = nil) {
runAction: RunAction? = nil,
archiveAction: ArchiveAction? = nil) {
self.name = name
self.shared = shared
self.buildAction = buildAction
self.testAction = testAction
self.runAction = runAction
self.archiveAction = archiveAction
}
}

Expand Down Expand Up @@ -132,3 +135,27 @@ public struct RunAction: Equatable, Codable {
arguments: arguments)
}
}

// MARK: - Archive Action

public struct ArchiveAction: Equatable, Codable {
public let configurationName: String
public let revealArchiveInOrganizer: Bool
public let customArchiveName: String?
public let preActions: [ExecutionAction]
public let postActions: [ExecutionAction]

public init(
configurationName: String,
revealArchiveInOrganizer: Bool = true,
customArchiveName: String? = nil,
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []
) {
self.configurationName = configurationName
self.revealArchiveInOrganizer = revealArchiveInOrganizer
self.customArchiveName = customArchiveName
self.preActions = preActions
self.postActions = postActions
}
}
44 changes: 42 additions & 2 deletions Sources/TuistCore/Models/Scheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ public class Scheme: Equatable {
public let buildAction: BuildAction?
public let testAction: TestAction?
public let runAction: RunAction?
public let archiveAction: ArchiveAction?

// MARK: - Init

public init(name: String,
shared: Bool = false,
buildAction: BuildAction? = nil,
testAction: TestAction? = nil,
runAction: RunAction? = nil) {
runAction: RunAction? = nil,
archiveAction: ArchiveAction? = nil) {
self.name = name
self.shared = shared
self.buildAction = buildAction
self.testAction = testAction
self.runAction = runAction
self.archiveAction = archiveAction
}

// MARK: - Equatable
Expand All @@ -31,7 +34,8 @@ public class Scheme: Equatable {
lhs.shared == rhs.shared &&
lhs.buildAction == rhs.buildAction &&
lhs.testAction == rhs.testAction &&
lhs.runAction == rhs.runAction
lhs.runAction == rhs.runAction &&
lhs.archiveAction == rhs.archiveAction
}
}

Expand Down Expand Up @@ -174,3 +178,39 @@ public class RunAction: Equatable {
lhs.arguments == rhs.arguments
}
}

public class ArchiveAction: Equatable {
// MARK: - Attributes

public let configurationName: String
public let revealArchiveInOrganizer: Bool
public let customArchiveName: String?
public let preActions: [ExecutionAction]
public let postActions: [ExecutionAction]

// MARK: - Init

public init(
configurationName: String,
revealArchiveInOrganizer: Bool = true,
customArchiveName: String? = nil,
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []
) {
self.configurationName = configurationName
self.revealArchiveInOrganizer = revealArchiveInOrganizer
self.customArchiveName = customArchiveName
self.preActions = preActions
self.postActions = postActions
}

// MARK: - Equatable

public static func == (lhs: ArchiveAction, rhs: ArchiveAction) -> Bool {
return lhs.configurationName == rhs.configurationName
&& lhs.revealArchiveInOrganizer == rhs.revealArchiveInOrganizer
&& lhs.customArchiveName == rhs.customArchiveName
&& lhs.preActions == rhs.preActions
&& lhs.postActions == rhs.postActions
}
}
22 changes: 19 additions & 3 deletions Sources/TuistCoreTesting/Models/Scheme+TestData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,32 @@ public extension BuildAction {
}
}

public extension Scheme {
extension ArchiveAction {
static func test(configurationName: String = "Beta Release",
revealArchiveInOrganizer: Bool = true,
customArchiveName: String? = nil,
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = []) -> ArchiveAction {
return ArchiveAction(configurationName: configurationName,
revealArchiveInOrganizer: revealArchiveInOrganizer,
customArchiveName: customArchiveName,
preActions: preActions,
postActions: postActions)
}
}

extension Scheme {
static func test(name: String = "Test",
shared: Bool = false,
buildAction: BuildAction? = BuildAction.test(),
testAction: TestAction? = TestAction.test(),
runAction: RunAction? = RunAction.test()) -> Scheme {
runAction: RunAction? = RunAction.test(),
archiveAction: ArchiveAction? = ArchiveAction.test()) -> Scheme {
return Scheme(name: name,
shared: shared,
buildAction: buildAction,
testAction: testAction,
runAction: runAction)
runAction: runAction,
archiveAction: archiveAction)
}
}
28 changes: 26 additions & 2 deletions Sources/TuistGenerator/Generator/SchemesGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ final class SchemesGenerator: SchemesGenerating {
let generatedTestAction = schemeTestAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedLaunchAction = schemeLaunchAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedProfileAction = schemeProfileAction(scheme: scheme, project: project, generatedProject: generatedProject)
let generatedArchiveAction = schemeArchiveAction(scheme: scheme, project: project, generatedProject: generatedProject)

let scheme = XCScheme(name: scheme.name,
lastUpgradeVersion: SchemesGenerator.defaultLastUpgradeVersion,
Expand All @@ -82,7 +83,7 @@ final class SchemesGenerator: SchemesGenerating {
launchAction: generatedLaunchAction,
profileAction: generatedProfileAction,
analyzeAction: schemeAnalyzeAction(for: project),
archiveAction: schemeArchiveAction(for: project))
archiveAction: generatedArchiveAction)
try scheme.write(path: schemePath.path, override: true)
}

Expand Down Expand Up @@ -147,6 +148,29 @@ final class SchemesGenerator: SchemesGenerating {
testables: testables)
}

/// Generates the scheme archive action.
/// - Parameter scheme: Scheme manifest.
/// - Parameter project: Project manifest.
/// - Parameter generatedProject: Generated Xcode project.
/// - Returns: Scheme archive action.
func schemeArchiveAction(scheme: Scheme,
project: Project,
generatedProject: GeneratedProject) -> XCScheme.ArchiveAction {
guard let archiveAction = scheme.archiveAction else {
return defaultSchemeArchiveAction(for: project)
}

return XCScheme.ArchiveAction(buildConfiguration: archiveAction.configurationName,
revealArchiveInOrganizer: archiveAction.revealArchiveInOrganizer,
customArchiveName: archiveAction.customArchiveName,
preActions: schemeExecutionActions(actions: archiveAction.preActions,
project: project,
generatedProject: generatedProject),
postActions: schemeExecutionActions(actions: archiveAction.postActions,
project: project,
generatedProject: generatedProject))
}

/// Generates the array of BuildableReference for targets that the
/// coverage report should be generated for them.
///
Expand Down Expand Up @@ -439,7 +463,7 @@ final class SchemesGenerator: SchemesGenerating {
/// Returns the scheme archive action
///
/// - Returns: Scheme archive action.
func schemeArchiveAction(for project: Project) -> XCScheme.ArchiveAction {
func defaultSchemeArchiveAction(for project: Project) -> XCScheme.ArchiveAction {
let buildConfiguration = defaultReleaseBuildConfigurationName(in: project)
return XCScheme.ArchiveAction(buildConfiguration: buildConfiguration,
revealArchiveInOrganizer: true)
Expand Down
17 changes: 17 additions & 0 deletions Sources/TuistKit/Generator/GeneratorModelLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ extension TuistCore.Scheme {
let buildAction = manifest.buildAction.map { TuistCore.BuildAction.from(manifest: $0) }
let testAction = manifest.testAction.map { TuistCore.TestAction.from(manifest: $0) }
let runAction = manifest.runAction.map { TuistCore.RunAction.from(manifest: $0) }
let archiveAction = manifest.archiveAction.map { TuistCore.ArchiveAction.from(manifest: $0) }

return Scheme(name: name,
shared: shared,
Expand Down Expand Up @@ -634,6 +635,22 @@ extension TuistCore.RunAction {
}
}

extension TuistCore.ArchiveAction {
static func from(manifest: ProjectDescription.ArchiveAction) -> TuistCore.ArchiveAction {
let configurationName = manifest.configurationName
let revealArchiveInOrganizer = manifest.revealArchiveInOrganizer
let customArchiveName = manifest.customArchiveName
let preActions = manifest.preActions.map { TuistCore.ExecutionAction.from(manifest: $0) }
let postActions = manifest.postActions.map { TuistCore.ExecutionAction.from(manifest: $0) }

return TuistCore.ArchiveAction(configurationName: configurationName,
revealArchiveInOrganizer: revealArchiveInOrganizer,
customArchiveName: customArchiveName,
preActions: preActions,
postActions: postActions)
}
}

extension TuistCore.ExecutionAction {
static func from(manifest: ProjectDescription.ExecutionAction) -> TuistCore.ExecutionAction {
return ExecutionAction(title: manifest.title, scriptText: manifest.scriptText, target: manifest.target)
Expand Down
20 changes: 18 additions & 2 deletions Tests/TuistGeneratorTests/Generator/SchemesGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,28 @@ final class SchemeGeneratorTests: XCTestCase {
XCTAssertEqual(got.buildConfiguration, "Debug")
}

func test_schemeArchiveAction() {
let got = subject.schemeArchiveAction(for: .test())
func test_defaultSchemeArchiveAction() {
let got = subject.defaultSchemeArchiveAction(for: .test())
XCTAssertEqual(got.buildConfiguration, "Release")
XCTAssertEqual(got.revealArchiveInOrganizer, true)
}

func test_schemeArchiveAction() {
let target = Target.test(name: "App", platform: .iOS, product: .app)
let scheme = Scheme.test(archiveAction: ArchiveAction.test(configurationName: "Beta Release",
revealArchiveInOrganizer: true,
customArchiveName: "App [Beta]"))
let pbxTarget = PBXNativeTarget(name: "App")
let project = Project.test(path: AbsolutePath("/project.xcodeproj"), targets: [target])
let generatedProject = GeneratedProject.test(targets: ["App": pbxTarget])

let got = subject.schemeArchiveAction(scheme: scheme, project: project, generatedProject: generatedProject)

XCTAssertEqual(got.buildConfiguration, "Beta Release")
XCTAssertEqual(got.customArchiveName, "App [Beta]")
XCTAssertEqual(got.revealArchiveInOrganizer, true)
}

// MARK: - Private

private func generatedProject(targets: [Target]) -> GeneratedProject {
Expand Down
55 changes: 55 additions & 0 deletions docs/usage/2-projectswift.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,14 @@ A `Scheme` defines a collection of targets to `Build, Run, Test, Profile, Analyz
optional: true,
default: 'nil',
},
{
name: 'Archive action',
description: 'Action that runs the project archive.',
type: 'ArchiveAction',
typeLink: '#archive-action',
optional: true,
default: 'nil',
},
]}
/>

Expand Down Expand Up @@ -908,6 +916,53 @@ Arguments contain commandline arguments passed on launch and Environment variabl
]}
/>

### Archive Action

<PropertiesTable
props={[
{
name: 'Configuration Name',
description:
'Indicates the build configuration to run the archive with.',
type: 'String',
optional: false,
default: '',
},
{
name: 'Reveal Archive in Organizer',
description:
'If set to true, Xcode will reveal the Organizer on completion.',
type: 'Bool',
optional: true,
default: 'true',
},
{
name: 'Custom Archive Name',
description:
'Set if you want to override Xcode's default archive name.',
type: 'String',
optional: true,
default: 'nil',
},
{
name: 'Pre-actions',
description:
'A list of actions that are executed before starting the archive process.',
type: '[ExecutionAction]',
optional: true,
default: '[]',
},
{
name: 'Post-actions',
description:
'A list of actions that are executed after the archive process.',
type: '[ExecutionAction]',
optional: true,
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:
Expand Down
2 changes: 2 additions & 0 deletions features/generate.feature
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,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 "Debug" for the configuration Debug
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

Scenario: The project is an iOS application with CocoaPods dependencies (ios_app_with_pods)
Given that tuist is available
Expand Down Expand Up @@ -227,6 +228,7 @@ Scenario: The project is an iOS application with extensions (ios_app_with_extens
Then I should be able to build for iOS the scheme App
Then the product 'App.app' with destination 'Debug-iphoneos' contains extension 'StickersPackExtension'
Then the product 'App.app' with destination 'Debug-iphoneos' contains extension 'NotificationServiceExtension'
Then the product 'App.app' with destination 'Debug-iphoneos' contains extension 'NotificationServiceExtension'

Scenario: The project is an iOS application with watch app (ios_app_with_watchapp2)
Given that tuist is available
Expand Down
7 changes: 4 additions & 3 deletions fixtures/ios_app_with_multi_configs/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ let settings = Settings(base: [
], configurations: configurations)

let betaScheme = Scheme(name: "App-Beta",
shared: true,
buildAction: BuildAction(targets: ["App"]),
runAction: RunAction(configurationName: "Beta", executable: "App"))
shared: true,
buildAction: BuildAction(targets: ["App"]),
runAction: RunAction(configurationName: "Beta", executable: "App"),
archiveAction: ArchiveAction(configurationName: "Beta"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we update a fixture test to ensure the archive scheme can execute successfully?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it needs to be updated, how do I run the fixtures with my version of tuist? Or is another thing that needs to change?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our fixtures are defined in fixtures/ and are exexuted by our cucumber test's.

To run them locally you would execute features from the Rakefile:

bundle exec rake features

Inside the generate feature you should be able to specify which action you would like Xcode to run as part of your scheme.

An example of this would be you can define a step in the cucumber tests as follows:

Then I should be able to archive for iOS the scheme App

If you are unsure of any of the above or would like me to step in then please ask

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but I don't know how this actually works. I wrote a new step as you suggested, but I'm getting the error error: use of unresolved identifier 'ArchiveAction' when a run bundle exec rake features, I guess it is because the tests aren't being run with my version of tuist.


let project = Project(name: "MainApp",
settings: settings,
Expand Down