diff --git a/build.gradle b/build.gradle index 8889fd2a..0fe87927 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,15 @@ +plugins { + id 'nebula.release' version '6.0.0' +} + +// + allprojects { apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' - def versionNumber = "0.16.0.a603076-SNAPSHOT" - - if (project.hasProperty("versionNumber")) { - versionNumber = project.versionNumber - } - if (project.hasProperty("versionSuffix")) { - versionNumber += project.versionSuffix - } - if (project.hasProperty("buildNumber")) { - versionNumber += "." + project.buildNumber - } - - group = 'org.openbakery' - version = versionNumber + version = project.version.toString() + "-SNAPSHOT" sourceCompatibility = "1.6" targetCompatibility = "1.6" diff --git a/example/OSX/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj b/example/OSX/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj index 5a9d55a3..0e7cec4c 100644 --- a/example/OSX/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj +++ b/example/OSX/ExampleOSX/ExampleOSX.xcodeproj/project.pbxproj @@ -187,7 +187,7 @@ TargetAttributes = { A7F1890E1A6FE161002D206F = { CreatedOnToolsVersion = 6.1.1; - DevelopmentTeam = Z7L2YCUH45; + DevelopmentTeam = 2YFT3F89TY; }; A7F189211A6FE161002D206F = { CreatedOnToolsVersion = 6.1.1; @@ -404,6 +404,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 2YFT3F89TY; INFOPLIST_FILE = ExampleOSX/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -417,6 +418,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "Developer ID Application"; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 2YFT3F89TY; INFOPLIST_FILE = ExampleOSX/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index b52aeeff..2f3dba20 100644 --- a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy +++ b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy @@ -23,7 +23,7 @@ import org.openbakery.output.OutputAppender import org.slf4j.Logger import org.slf4j.LoggerFactory -class CommandRunner { +class CommandRunner implements Serializable{ private static Logger logger = LoggerFactory.getLogger(CommandRunner.class) @@ -34,10 +34,6 @@ class CommandRunner { Thread readerThread - public CommandRunner() { - - } - void setOutputFile(File outputFile) { if (outputFile.exists()) { diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index 89f80ad2..274fb4df 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -58,7 +58,7 @@ class Xcode { if (file.exists()) { result.put(ENV_DEVELOPER_DIR, file.absolutePath) } - println file.absolutePath + return result } diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index b84bae48..dc6a1243 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -50,26 +50,34 @@ class Xcodebuild { static void packageIpa(CommandRunner commandRunner, File archivePath, File exportPath, - File exportOptionsPlist) { + File exportOptionsPlist, + @Nullable File xcodeApp) { assert archivePath != null && archivePath.exists() assert exportPath != null && exportPath.exists() assert exportOptionsPlist != null && exportOptionsPlist.exists() - commandRunner.run(EXECUTABLE, - ACTION_EXPORT_ARCHIVE, - ARGUMENT_ARCHIVE_PATH, archivePath.absolutePath, - ARGUMENT_EXPORT_PATH, exportPath.absolutePath, - ARGUMENT_EXPORT_OPTIONS_PLIST, exportOptionsPlist.absolutePath) + // Env value + HashMap envMap = new HashMap<>() + if (xcodeApp != null) { + envMap.put(Xcode.ENV_DEVELOPER_DIR, xcodeApp.absolutePath) + } + + List args = [EXECUTABLE, + ACTION_EXPORT_ARCHIVE, + ARGUMENT_ARCHIVE_PATH, archivePath.absolutePath, + ARGUMENT_EXPORT_PATH, exportPath.absolutePath, + ARGUMENT_EXPORT_OPTIONS_PLIST, exportOptionsPlist.absolutePath] + + commandRunner.run(args, envMap) } static void archive(CommandRunner commandRunner, String scheme, File outputPath, - File xcConfig, + String configuration, @Nullable File xcodeApp) { assert scheme != null - assert xcConfig.exists() && !xcConfig.isDirectory() HashMap envMap = new HashMap<>() @@ -80,8 +88,8 @@ class Xcodebuild { List args = [EXECUTABLE, ACTION_ARCHIVE, ARGUMENT_SCHEME, scheme, - ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, - ARGUMENT_XCCONFIG, xcConfig.absolutePath] + "-configuration", configuration, + ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath] commandRunner.run(args, envMap) } diff --git a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy index c93801a1..71b02662 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy @@ -75,7 +75,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "$certificate.absolutePath" } } """ @@ -84,6 +84,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments(KeychainCreateTask.TASK_NAME) + .withDebug(true) .withPluginClasspath(pluginClasspath) .build() @@ -96,7 +97,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" } } @@ -107,6 +108,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { .withProjectDir(testProjectDir.root) .withArguments(KeychainCreateTask.TASK_NAME) .withPluginClasspath(pluginClasspath) + .withDebug(true) .build() then: @@ -118,7 +120,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" } } diff --git a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy new file mode 100644 index 00000000..0587774e --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy @@ -0,0 +1,140 @@ +package org.openbakery.carthage + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class CarthageBootStrapTaskFunctionalTest extends Specification { + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + List pluginClasspath + File buildFile + GradleRunner gradleRunner + File carthageFolder + + void setup() { + buildFile = testProjectDir.newFile('build.gradle') + + buildFile << """ + plugins { + id 'org.openbakery.xcode-plugin' + } + """ + + def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { + throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") + } + + pluginClasspath = pluginClasspathResource.readLines().collect { new File(it) } + + gradleRunner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(CarthageBootStrapTask.NAME) + .withPluginClasspath(pluginClasspath) + + carthageFolder = new File(testProjectDir.root, "Carthage") + } + + def "The task list should contain the task"() { + when: + BuildResult result = gradleRunner.build() + + then: + result.output.contains(CarthageBootStrapTask.NAME) + } + + def "The task should be skipped if no cartfile is present"() { + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SKIPPED + } + + def "The task should be executed with success if a `cartfile.resolved` file is present"() { + setup: + testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + } + + def "The task should resolve the defined carthage dependencies"() { + setup: + File carthageFile = testProjectDir.newFile("Cartfile") + carthageFile << """ + github "ashleymills/Reachability.swift" + """ + + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + carthageResolvedFile << """ + github "ashleymills/Reachability.swift" "v4.1.0" + """ + + when: + BuildResult result = gradleRunner + .build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The resolved framework should be existing only for iOS (default target)" + carthageFolder.exists() + new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + !new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + + when: "Force reset and build with cache enabled" + assert carthageFolder.deleteDir() + result = gradleRunner.withArguments('--build-cache', CarthageBootStrapTask.NAME) + .build() + + then: "Should resolve the carthage dependencies from cache" + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.FROM_CACHE + + new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + !new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + } + + def "The task should resolve the defined carthage dependencies depending of the configured target"() { + setup: + File carthageFile = testProjectDir.newFile("Cartfile") + carthageFile << """ + github "ashleymills/Reachability.swift" + """ + + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + carthageResolvedFile << """ + github "ashleymills/Reachability.swift" "v4.1.0" + """ + + buildFile << """ + xcodebuild { + type = "tvOS" + } + """ + + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The resolved framework should be existing only for iOS (default target)" + carthageFolder.exists() + !new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + } +} diff --git a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy index d20157ff..16dce6f6 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy @@ -30,7 +30,9 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { provisioningFile1 = findResource("test1.mobileprovision") assert provisioningFile1.exists() - def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + def pluginClasspathResource = getClass().classLoader + .findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") } @@ -70,7 +72,7 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - mobileProvisionURI = [] + mobileProvisionList = [] } } """ diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index b50c49a7..edd69479 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -107,7 +107,7 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { } String getBundleIdentifier() { - File infoPlist = new File(project.projectDir, getXcodeExtension().infoPlist) + File infoPlist = new File(project.rootProject.rootDir, getXcodeExtension().infoPlist) return plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") } @@ -119,8 +119,6 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { List provisioningList = getProvisioningUriList() .collect { it -> new File(new URI(it)) } - println "provisioningList : " + provisioningList - return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, provisioningList, commandRunner, diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 51b972a5..dda4ad00 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -43,7 +43,7 @@ class InfoPlistModifyTask extends AbstractDistributeTask { throw new IllegalArgumentException("No Info.plist was found! Check you xcode project settings if the specified target has a Info.plist set.") } - infoPlist = new File(project.projectDir, project.xcodebuild.infoPlist) + infoPlist = new File(project.rootProject.projectDir, project.xcodebuild.infoPlist) logger.debug("Try to updating {}", infoPlist) @@ -148,7 +148,7 @@ class InfoPlistModifyTask extends AbstractDistributeTask { setValueForPlist(KeyBundleIdentifier, extension.bundleIdentifier) } else { xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme.getOrNull(), - xcodeExtension.configuration) + xcodeExtension.configuration.get()) .map { it -> it.bundleIdentifier } .ifPresent { it -> setValueForPlist(KeyBundleIdentifier, it) } } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 57364b9c..d812e2c2 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -11,6 +11,7 @@ import org.gradle.api.tasks.* import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask +import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper @CompileStatic @@ -21,7 +22,14 @@ class PrepareXcodeArchivingTask extends DefaultTask { final Provider entitlementsFile = newInputFile() @OutputFile - final Provider outputFile = newOutputFile() + final Property outputFile = newOutputFile() + + @InputDirectory + final Provider projectFile = newInputFile() + + final Provider scheme = project.objects.property(String) + final Provider buildConfiguration = project.objects.property(String) + final Provider target = project.objects.property(String) final ListProperty registeredProvisioningFiles = project.objects.listProperty(File) final Property commandRunnerProperty = project.objects.property(CommandRunner) @@ -79,38 +87,98 @@ class PrepareXcodeArchivingTask extends DefaultTask { } })) + this.outputFile.set(project.layout + .buildDirectory + .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) + this.onlyIf { return certificateFriendlyName.present && configurationBundleIdentifier.present && - outputFile.present && provisioningForConfiguration.present } } + private File getPbxProjFile() { + return new File(projectFile.get().asFile, "project.pbxproj") + } + + private Serializable getValueFromPbxProjFile(String value) { + return plistHelperProperty.get() + .getValueFromPlist(toXml(getPbxProjFile()), value) as Serializable + } + + private Serializable getObjectValueFromPbxProjFile(String value) { + return getValueFromPbxProjFile("objects:${value}") + } + + private String findProductId(String rootKey) { + return getValueFromPbxProjFile("objects:${rootKey}:targets") + .find { it -> getObjectValueFromPbxProjFile("${it}:productName") == target.get() } + } + + private String getBuildConfigurationIdentifier(String targetId) { + String configurationId = getObjectValueFromPbxProjFile("$targetId:buildConfigurationList") + List list = getObjectValueFromPbxProjFile("${configurationId}:buildConfigurations") as List + return list.find { + getValueFromPbxProjFile("objects:${it}:name") == buildConfiguration.get() + } + } + + private void setBuildConfigurationBuildSetting(String bcId, + String key, + String value) { + String completeKey = "objects:${bcId}:buildSettings:${key}" + Object property = plistHelperProperty.get().getValueFromPlist(getPbxProjFile(), completeKey) + + if (property == null) { + plistHelperProperty.get() + .addValueForPlist(getPbxProjFile(), completeKey, value) + } else { + + plistHelperProperty.get() + .setValueForPlist(getPbxProjFile(), completeKey, value) + } + } + @TaskAction void generate() { - logger.info("Preparing archiving") + String rootKey = getValueFromPbxProjFile("rootObject") + + String buildConfigurationId = getBuildConfigurationIdentifier(findProductId(rootKey)) + + HashMap map = new HashMap<>() - outputFile.get().asFile.text = "" + map.put("CODE_SIGN_STYLE", "Manual") - append(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) - append(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) + map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) + map.put("CODE_SIGN_IDENTITY[sdk=iphoneos*]", certificateFriendlyName.get()) + map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) if (provisioningReader.present) { ProvisioningProfileReader reader = provisioningReader.get() - append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) - append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) - append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) + map.put(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) + map.put(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) + map.put(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) } - if (entitlementsFilePath.present) { - append(KEY_CODE_SIGN_ENTITLEMENTS, entitlementsFilePath.get()) + if (entitlementsFile.present) { + map.put("CODE_SIGN_ENTITLEMENTS", entitlementsFile.get().asFile.absolutePath) + } + + map.each { k, v -> + setBuildConfigurationBuildSetting(buildConfigurationId, k, v) } } - private void append(String key, String value) { - outputFile.get() - .asFile - .append(System.getProperty("line.separator") + key + " = " + value) + private File toXml(File source) { + File file = File.createTempFile("project.plist", "") + commandRunnerProperty.get() + .run(["plutil", + "-convert", + "xml1", + source.absolutePath, + "-o", file.absolutePath]) + + return file } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 4823ee50..b68305ca 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -35,6 +35,9 @@ class XcodeBuildPluginExtension { final Property bitcode = project.objects.property(Boolean) final Property version = project.objects.property(String) + final Property configuration = project.objects.property(String) + final Property target = project.objects.property(String) + final Property targetType = project.objects.property(Type) final Property scheme = project.objects.property(String) final DirectoryProperty archiveDirectory = project.layout.directoryProperty() final DirectoryProperty schemeArchiveFile = project.layout.directoryProperty() @@ -51,12 +54,9 @@ class XcodeBuildPluginExtension { String infoPlist = null - String configuration = 'Debug' boolean simulator = true Type type = Type.iOS - String target - def additionalParameters = null String bundleNameSuffix = null List arch = null @@ -108,6 +108,8 @@ class XcodeBuildPluginExtension { this.symRoot.set(project.layout.buildDirectory.dir("sym")) this.sharedPrecompsDir.set(project.layout.buildDirectory.dir("shared")) this.derivedDataPath.set(project.layout.buildDirectory.dir("derivedData")) + + this.targetType.set(Type.iOS) } private void configureServices() { @@ -257,7 +259,7 @@ class XcodeBuildPluginExtension { // should be removed an replaced by the xcodebuildParameters.outputPath File getOutputPath() { - String path = getConfiguration() + String path = configuration.get() if (type != Type.macOS) { path += "-" if (type == Type.iOS) { @@ -286,7 +288,7 @@ class XcodeBuildPluginExtension { projectSettings.each { String key, BuildTargetConfiguration buildConfiguration -> - BuildConfiguration settings = buildConfiguration.buildSettings[configuration]; + BuildConfiguration settings = buildConfiguration.buildSettings[configuration.get()]; if (settings != null && settings.bundleIdentifier.equalsIgnoreCase(bundleIdentifier)) { result = settings return @@ -300,9 +302,9 @@ class XcodeBuildPluginExtension { File getApplicationBundle() { - BuildTargetConfiguration buildConfiguration = projectSettings[target] + BuildTargetConfiguration buildConfiguration = projectSettings[target.get()] if (buildConfiguration != null) { - BuildConfiguration buildSettings = buildConfiguration.buildSettings[configuration]; + BuildConfiguration buildSettings = buildConfiguration.buildSettings[configuration.get()]; if (buildSettings != null && buildSettings.sdkRoot.equalsIgnoreCase("watchos")) { BuildConfiguration parent = getParent(buildSettings) return new File(getOutputPath(), parent.productName + "." + this.productType) @@ -313,9 +315,9 @@ class XcodeBuildPluginExtension { File getBinary() { logger.debug("getBinary") - BuildTargetConfiguration buildConfiguration = projectSettings[target] + BuildTargetConfiguration buildConfiguration = projectSettings[target.get()] if (buildConfiguration != null) { - BuildConfiguration buildSettings = buildConfiguration.buildSettings[configuration]; + BuildConfiguration buildSettings = buildConfiguration.buildSettings[configuration.get()]; logger.debug("buildSettings: {}", buildSettings) if (type == Type.macOS) { return new File(getOutputPath(), buildSettings.productName + ".app/Contents/MacOS/" + buildSettings.productName) @@ -327,17 +329,17 @@ class XcodeBuildPluginExtension { BuildConfiguration getBuildConfiguration() { - BuildTargetConfiguration buildTargetConfiguration = projectSettings[target] + BuildTargetConfiguration buildTargetConfiguration = projectSettings[target.get()] if (buildTargetConfiguration != null) { - return buildTargetConfiguration.buildSettings[configuration]; + return buildTargetConfiguration.buildSettings[configuration.get()]; } - throw new IllegalStateException("No build configuration found for + target '" + parameters.target + "' and configuration '" + configuration + "'") + throw new IllegalStateException("No build configuration found for + target '" + parameters.target.get() + "' and configuration '" + configuration.get() + "'") } BuildConfiguration getBuildConfiguration(String bundleIdentifier) { BuildConfiguration result = null projectSettings.each() { target, buildTargetConfiguration -> - BuildConfiguration settings = buildTargetConfiguration.buildSettings[configuration] + BuildConfiguration settings = buildTargetConfiguration.buildSettings[configuration.get()] if (settings != null) { @@ -358,6 +360,7 @@ class XcodeBuildPluginExtension { void setType(String type) { this.type = Type.typeFromString(type) + this.targetType.set(this.type) } Type getType() { @@ -379,10 +382,12 @@ class XcodeBuildPluginExtension { this.simulator = simulator.toString().equalsIgnoreCase("true") || simulator.toString().equalsIgnoreCase("yes") } - void setProjectFile(def projectFile) { - if (projectFile instanceof File) { - this.projectFile = projectFile - } + void setProjectFile(File projectFile) { + assert projectFile.exists() + this.projectFile = projectFile + } + + void setProjectFile(String projectFile) { this.projectFile = new File(project.projectDir.absolutePath, projectFile) } @@ -391,12 +396,12 @@ class XcodeBuildPluginExtension { return this.projectFile } - String[] projectFiles = project.projectDir.list(new SuffixFileFilter(".xcodeproj")) + String[] projectFiles = project.rootProject.projectDir.list(new SuffixFileFilter(".xcodeproj")) if (!projectFiles || projectFiles.length < 1) { throw new FileNotFoundException("No Xcode project files were found in ${project.projectDir}") } - return new File(project.projectDir, projectFiles.first()) + return new File(project.rootProject.projectDir, projectFiles.first()) } // should be remove in the future, so that every task has its own xcode object @@ -412,11 +417,11 @@ class XcodeBuildPluginExtension { XcodebuildParameters getXcodebuildParameters() { def result = new XcodebuildParameters() result.scheme = this.scheme.getOrNull() - result.target = this.target + result.target = this.target.get() result.simulator = this.simulator result.type = this.type result.workspace = getWorkspace() - result.configuration = this.configuration + result.configuration = this.configuration.get() result.dstRoot = this.getDstRoot().asFile.getOrNull() result.objRoot = this.getObjRoot().asFile.getOrNull() result.symRoot = this.getSymRoot().asFile.getOrNull() diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 60727419..24e2e2db 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -116,7 +116,6 @@ class XcodePlugin implements Plugin { public static final String OCLINT_TASK_NAME = 'oclint' public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' public static final String CPD_TASK_NAME = 'cpd' - public static final String CARTHAGE_BOOTSTRAP_TASK_NAME = 'carthageBootstrap' public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' @@ -134,7 +133,6 @@ class XcodePlugin implements Plugin { private Signing signingExtension private XcodeBuildPluginExtension xcodeBuildPluginExtension private InfoPlistExtension infoPlistExtension - private CommandRunner commandRunner private PlistHelper plistHelper private Security securityTool @@ -489,26 +487,32 @@ class XcodePlugin implements Plugin { .create(PrepareXcodeArchivingTask.NAME, PrepareXcodeArchivingTask.class) { it.group = XCODE_GROUP_NAME - it.certificateFriendlyName.set(signingExtension.certificateFriendlyName) it.commandRunnerProperty.set(commandRunner) it.configurationBundleIdentifier.set(infoPlistExtension.configurationBundleIdentifier) it.entitlementsFile.set(signingExtension.entitlementsFile) - it.outputFile.set(signingExtension.xcConfigFile) + it.projectFile.set(xcodeBuildPluginExtension.projectFile) + signingExtension.xcConfigFile.set(it.outputFile) it.plistHelperProperty.set(plistHelper) it.registeredProvisioningFiles.set(signingExtension.registeredProvisioningFiles) + + it.buildConfiguration.set(xcodeBuildPluginExtension.configuration) + it.scheme.set(xcodeBuildPluginExtension.scheme) + it.target.set(xcodeBuildPluginExtension.target) + it.xcodeVersion.set(xcodeBuildPluginExtension.version) + it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) { it.setGroup(XCODE_GROUP_NAME) it.buildType.set(xcodeBuildPluginExtension.type) + it.buildConfiguration.set(xcodeBuildPluginExtension.configuration) it.commandRunnerProperty.set(commandRunner) it.outputArchiveFile.set(xcodeBuildPluginExtension.schemeArchiveFile) it.scheme.set(xcodeBuildPluginExtension.scheme) it.xcode.set(xcode) it.xcodeVersion.set(xcodeBuildPluginExtension.version) - it.xcConfigFile.set(signingExtension.xcConfigFile) it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } @@ -522,7 +526,7 @@ class XcodePlugin implements Plugin { } private void configureSimulatorTasks(Project project) { - project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask.class, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) @@ -692,11 +696,17 @@ class XcodePlugin implements Plugin { private void configureCarthage(Project project) { project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) - project.task(CARTHAGE_BOOTSTRAP_TASK_NAME, type: CarthageBootStrapTask, group: CARTHAGE_GROUP_NAME) + + project.tasks.create(CarthageBootStrapTask.NAME, CarthageBootStrapTask.class) { + it.group = CARTHAGE_GROUP_NAME + it.requiredXcodeVersion.set(xcodeBuildPluginExtension.version) + it.commandRunnerProperty.set(commandRunner) + it.platform.set(xcodeBuildPluginExtension.targetType) + } } private configureCarthageDependencies(Project project) { - CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CARTHAGE_BOOTSTRAP_TASK_NAME) + CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CarthageBootStrapTask.NAME) as CarthageBootStrapTask addDependencyToBuild(project, bootStrapTask) project.getTasks() diff --git a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy index ce139146..05ea6f24 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy @@ -97,14 +97,13 @@ class XcodeProjectFile { throw new IllegalArgumentException("Project file does not exist: " + this.projectFile) } - if (project.xcodebuild.target == null) { + if (!project.xcodebuild.target.present) { throw new IllegalArgumentException("'xcodebuild.target' is null"); } - BuildConfiguration settings = getBuildConfiguration(project.xcodebuild.target, project.xcodebuild.configuration) + BuildConfiguration settings = getBuildConfiguration(project.xcodebuild.target.get(), project.xcodebuild.configuration.get()) logger.debug("rootObjectKey {}", rootObjectKey); - verifyTarget(project.xcodebuild.target) - + verifyTarget(project.xcodebuild.target.get()) if (StringUtils.isEmpty(project.xcodebuild.productName)) { project.xcodebuild.productName = settings.productName diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index f1ebe023..142046c2 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -5,12 +5,10 @@ import org.gradle.api.DefaultTask import org.gradle.api.Task import org.gradle.api.Transformer import org.gradle.api.file.Directory -import org.gradle.api.file.RegularFile import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.openbakery.CommandRunner @@ -33,8 +31,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { @Input final Provider buildType = project.objects.property(Type) - @InputFile - final Property xcConfigFile = newInputFile() + final Provider buildConfiguration = project.objects.property(String) @OutputDirectory final Provider outputArchiveFile = newOutputDirectory() @@ -65,17 +62,17 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { void archive() { assert scheme.present: "No target scheme configured" assert outputArchiveFile.present: "No output file folder configured" - assert xcConfigFile.present: "No 'xcconfig' file configured" + + outputArchiveFile.get().asFile.parentFile.mkdirs() logger.lifecycle("Archive project with configuration: " + "\n\tScheme : ${scheme.get()} " + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}") - Xcodebuild.archive(commandRunnerProperty.get(), scheme.get(), outputArchiveFile.get().asFile, - xcConfigFile.get().asFile, + buildConfiguration.get(), getXcodeAppForConfiguration().getOrNull()) } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy index abbb6664..d26c96ad 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -1,10 +1,14 @@ package org.openbakery.carthage +import groovy.transform.CompileStatic import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeTask +import org.openbakery.CommandRunnerException +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.xcode.Type +@CompileStatic abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { static final String ACTION_BOOTSTRAP = "bootstrap" @@ -31,7 +35,6 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @InputFile @Optional - @PathSensitive(PathSensitivity.RELATIVE) Provider getCartFile() { // Cf https://github.com/gradle/gradle/issues/2016 File file = project.rootProject.file(CARTHAGE_FILE) @@ -43,7 +46,6 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @InputFile @Optional - @PathSensitive(PathSensitivity.RELATIVE) Provider getCartResolvedFile() { // Cf https://github.com/gradle/gradle/issues/2016 File file = project.rootProject.file(CARTHAGE_FILE_RESOLVED) @@ -55,7 +57,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @Input String getCarthagePlatformName() { - switch (project.xcodebuild.type) { + switch (project.extensions.findByType(XcodeBuildPluginExtension).type) { case Type.iOS: return CARTHAGE_PLATFORM_IOS case Type.tvOS: return CARTHAGE_PLATFORM_TVOS case Type.macOS: return CARTHAGE_PLATFORM_MACOS @@ -65,6 +67,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { } @OutputDirectory + @PathSensitive(PathSensitivity.NAME_ONLY) Provider getOutputDirectory() { return project.provider { project.rootProject.file("Carthage/Build/" + getCarthagePlatformName()) @@ -74,14 +77,14 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { String getCarthageCommand() { try { return commandRunner.runWithResult("which", "carthage") - } catch (CommandRunnerException) { + } catch (CommandRunnerException exception) { // ignore, because try again with full path below } try { commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) return CARTHAGE_USR_BIN_PATH - } catch (CommandRunnerException) { + } catch (CommandRunnerException exception) { // ignore, because blow an exception is thrown } throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index 7c6e8c43..94df3517 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -1,35 +1,154 @@ package org.openbakery.carthage import groovy.transform.CompileStatic -import org.gradle.api.tasks.TaskAction -import org.gradle.internal.logging.text.StyledTextOutputFactory -import org.openbakery.output.ConsoleOutputAppender +import org.gradle.api.Action +import org.gradle.api.DefaultTask +import org.gradle.api.Transformer +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.process.ExecSpec +import org.gradle.workers.WorkerExecutor +import org.openbakery.CommandRunner +import org.openbakery.CommandRunnerException +import org.openbakery.xcode.Type +import org.openbakery.xcode.Xcode +import javax.inject.Inject + +@CacheableTask @CompileStatic -class CarthageBootStrapTask extends AbstractCarthageTaskBase { +class CarthageBootStrapTask extends DefaultTask { + + @Input + @Optional + Property requiredXcodeVersion = project.objects.property(String) + + @Input + Property carthagePlatformName = project.objects.property(String) + + @InputFile + @PathSensitive(PathSensitivity.NAME_ONLY) + RegularFileProperty cartFile = project.layout.fileProperty() + + @OutputDirectory + Property outputDirectory = project.objects.property(File) + + public static final String NAME = "carthageBootstrap" + + final Property platform = project.objects.property(Type) + final Property xcodeProperty = project.objects.property(Xcode) + final Property commandRunnerProperty = project.objects.property(CommandRunner) + + final WorkerExecutor workerExecutor - CarthageBootStrapTask() { + static final String CARTHAGE_FILE = "Cartfile.resolved" + static final String CARTHAGE_PLATFORM_IOS = "iOS" + static final String CARTHAGE_PLATFORM_MACOS = "Mac" + static final String CARTHAGE_PLATFORM_TVOS = "tvOS" + static final String CARTHAGE_PLATFORM_WATCHOS = "watchOS" + static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" + static final String ACTION_BOOTSTRAP = "bootstrap" + static final String ARG_PLATFORM = "--platform" + static final String ARG_CACHE_BUILDS = "--cache-builds" + + @Inject + CarthageBootStrapTask(WorkerExecutor workerExecutor) { super() + this.workerExecutor = workerExecutor + setDescription "Check out and build the Carthage project dependencies" + + cartFile.set(new File(project.rootProject.rootDir, CARTHAGE_FILE)) + + carthagePlatformName.set(platform.map(new Transformer() { + @Override + String transform(Type type) { + return typeToCarthagePlatform(type) + } + })) + + outputDirectory.set(carthagePlatformName.map(new Transformer() { + @Override + File transform(String platformName) { + return new File(project.rootProject.rootDir, "Carthage/Build/" + platformName) + } + })) + + xcodeProperty.set(commandRunnerProperty.map(new Transformer() { + @Override + Xcode transform(CommandRunner commandRunner) { + return new Xcode(commandRunner) + } + })) + + onlyIf { + return cartFile.asFile.get().exists() + } + } + + void setXcode(Xcode xcode) { + this.xcode = xcode } @TaskAction void update() { - if (hasCartFile()) { - logger.info('Boostrap Carthage for platform ' + carthagePlatformName) - def output = services.get(StyledTextOutputFactory) - .create(CarthageBootStrapTask) - - List args = [getCarthageCommand(), - ACTION_BOOTSTRAP, + logger.warn('Bootstrap Carthage for platform ' + carthagePlatformName) + project.exec(new Action() { + @Override + void execute(ExecSpec execSpec) { + execSpec.args = [ACTION_BOOTSTRAP, + ARG_CACHE_BUILDS, + "--new-resolver", + "--color", "always", ARG_PLATFORM, - carthagePlatformName, - ARG_CACHE_BUILDS] + carthagePlatformName.getOrNull().toString()] as List + + execSpec.environment(getEnvValues()) + execSpec.executable = getCarthageCommand() + execSpec.workingDir(project.rootProject.projectDir) + } + }) + } - commandRunner.run(project.projectDir.absolutePath, - args, - getRequiredXcodeVersion() != null ? xcode.getXcodeSelectEnvValue(getRequiredXcodeVersion()) : null, - new ConsoleOutputAppender(output)) + private final Map getEnvValues() { + final Map envValues + if (requiredXcodeVersion.present) { + envValues = xcodeProperty.get() + .getXcodeSelectEnvValue(requiredXcodeVersion.getOrNull()) + } else { + envValues = [:] } + + return envValues + } + + private String typeToCarthagePlatform(Type type) { + switch (type) { + case Type.iOS: return CARTHAGE_PLATFORM_IOS + case Type.tvOS: return CARTHAGE_PLATFORM_TVOS + case Type.macOS: return CARTHAGE_PLATFORM_MACOS + case Type.watchOS: return CARTHAGE_PLATFORM_WATCHOS + default: return 'all' + } + } + + private String getCarthageCommand() { + try { + return commandRunnerProperty.get() + .runWithResult("which", "carthage") + } catch (CommandRunnerException exception) { + // ignore, because try again with full path below + } + + try { + commandRunnerProperty.get() + .runWithResult("ls", CARTHAGE_USR_BIN_PATH) + return CARTHAGE_USR_BIN_PATH + } catch (CommandRunnerException exception) { + // ignore, because blow an exception is thrown + } + + throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") } } diff --git a/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy b/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy index 4c47646e..5f677228 100644 --- a/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy @@ -94,7 +94,7 @@ class CoverageTask extends AbstractXcodeTask { } def possibleDirectories = [ - "Build/Intermediates/CodeCoverage/" + project.xcodebuild.target + "/Coverage.profdata", + "Build/Intermediates/CodeCoverage/" + project.xcodebuild.target.get() + "/Coverage.profdata", "Build/Intermediates/CodeCoverage/Coverage.profdata" ] diff --git a/plugin/src/main/groovy/org/openbakery/cpd/CpdTask.groovy b/plugin/src/main/groovy/org/openbakery/cpd/CpdTask.groovy index 70e9d78c..2a186fad 100644 --- a/plugin/src/main/groovy/org/openbakery/cpd/CpdTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/cpd/CpdTask.groovy @@ -47,7 +47,7 @@ class CpdTask extends AbstractXcodeTask { "-cp", "\"${cp.join(':')}\"", 'net.sourceforge.pmd.cpd.CPD', "--minimum-tokens", "10", - "--files", "${projectDir.absolutePath}/${xcodebuild.target}", "${projectDir.absolutePath}/${xcodebuild.target}Tests", + "--files", "${projectDir.absolutePath}/${xcodebuild.target.get()}", "${projectDir.absolutePath}/${xcodebuild.target}Tests", "--language", "ObjectiveC", "--encoding", "UTF-8", "--format", "net.sourceforge.pmd.cpd.XMLRenderer" diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 6d93319a..a3847149 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -11,7 +11,6 @@ import org.openbakery.CommandRunner import org.openbakery.codesign.CodesignParameters import org.openbakery.signing.ProvisioningFile import org.openbakery.signing.SigningMethod -import org.openbakery.util.PathHelper import javax.inject.Inject @@ -69,10 +68,6 @@ class Signing { + System.currentTimeMillis() + ".keychain")) this.timeout.set(3600) - - this.xcConfigFile.set(project.layout - .buildDirectory - .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) } void setKeychain(Object keychain) { @@ -82,7 +77,8 @@ class Signing { this.keychain.set(project.file(keychain)) } - public void setMethod(String method) { + void setMethod(String method) { + println "setMethod : " + method signingMethod.set(SigningMethod.fromString(method) .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") @@ -145,7 +141,7 @@ class Signing { } @Override - public String toString() { + String toString() { if (this.keychain != null) { return "Signing{" + " identity='" + identity + '\'' + diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 5f13fdc6..320f5fef 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -4,12 +4,14 @@ import groovy.transform.CompileStatic import groovy.transform.TypeCheckingMode import org.gradle.api.DefaultTask import org.gradle.api.Task +import org.gradle.api.Transformer import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.CommandRunner import org.openbakery.XcodePlugin +import org.openbakery.XcodeService import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningFile import org.openbakery.signing.ProvisioningInstallTask @@ -22,6 +24,9 @@ import org.openbakery.xcode.Xcodebuild @CompileStatic class PackageTaskIosAndTvOS extends DefaultTask { + @Input + final Provider xcodeVersion = project.objects.property(String) + @Input public final Property signingMethod = project.objects.property(SigningMethod) @@ -42,6 +47,8 @@ class PackageTaskIosAndTvOS extends DefaultTask { final Provider commandRunner = project.objects.property(CommandRunner) final Provider plistHelper = project.objects.property(PlistHelper) + final Property xcodeServiceProperty = project.objects.property(XcodeService) + public static final String DESCRIPTION = "Package the archive with Xcode-build" public static final String NAME = "packageWithXcodeBuild" @@ -162,6 +169,24 @@ class PackageTaskIosAndTvOS extends DefaultTask { Xcodebuild.packageIpa(commandRunner.get(), getArchiveFile(), getOutputDirectory(), - getExportOptionsPlistFile()) + getExportOptionsPlistFile(), + getXcodeAppForConfiguration().getOrNull()) + } + + private Provider getXcodeAppForConfiguration() { + + Provider xcodeApp + if (xcodeVersion.present) { + xcodeApp = xcodeServiceProperty.map(new Transformer() { + @Override + File transform(XcodeService xcodeService) { + XcodeService.XcodeApp app = xcodeService.getInstallationForVersion(xcodeVersion.get()) + return app.contentDeveloperFile + } + }) + } else { + xcodeApp = project.objects.property(File) + } + return xcodeApp } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 92d913fb..ab71ba10 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -43,7 +43,9 @@ class ProvisioningInstallTask extends Download { super() this.description = TASK_DESCRIPTION - this.onlyIf { !mobileProvisioningList.get().empty } + this.onlyIf { + !mobileProvisioningList.get().empty + } } @TaskAction diff --git a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy index 307710f1..94efc93c 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy @@ -20,6 +20,7 @@ enum SigningMethod { } static Optional fromString(value) { + println "fromString : " + value return Optional.ofNullable(values().find { it.getValue() == value }) } } diff --git a/plugin/src/main/groovy/org/openbakery/util/VariableResolver.groovy b/plugin/src/main/groovy/org/openbakery/util/VariableResolver.groovy index 895a0881..5111dbae 100644 --- a/plugin/src/main/groovy/org/openbakery/util/VariableResolver.groovy +++ b/plugin/src/main/groovy/org/openbakery/util/VariableResolver.groovy @@ -57,7 +57,7 @@ class VariableResolver { return [ "PRODUCT_NAME": project.xcodebuild.productName, "SRC_ROOT" : project.projectDir.absolutePath, - "TARGET_NAME" : project.xcodebuild.target + "TARGET_NAME" : project.xcodebuild.target.get() ] } -} \ No newline at end of file +} diff --git a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy deleted file mode 100644 index 8f45eeb5..00000000 --- a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy +++ /dev/null @@ -1,150 +0,0 @@ -package org.openbakery.carthage - -import org.gradle.api.Project -import org.gradle.api.provider.Provider -import org.gradle.testfixtures.ProjectBuilder -import org.junit.Rule -import org.junit.rules.ExpectedException -import org.openbakery.CommandRunner -import org.openbakery.output.ConsoleOutputAppender -import org.openbakery.xcode.Xcode -import spock.lang.Specification -import spock.lang.Unroll - -import static org.openbakery.carthage.AbstractCarthageTaskBase.* -import static org.openbakery.xcode.Type.* - -class CarthageBootStrapTaskTest extends Specification { - - CarthageBootStrapTask subject - CommandRunner commandRunner = Mock(CommandRunner) - Xcode mockXcode = Mock(Xcode) - File projectDir - File cartFile - Project project - - @Rule - public ExpectedException exception = ExpectedException.none() - - void setup() { - projectDir = File.createTempDir() - - cartFile = new File(projectDir, "Cartfile") - cartFile << 'github "Alamofire/Alamofire"' - - project = ProjectBuilder.builder() - .withProjectDir(projectDir) - .build() - - project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin - - subject = project.getTasks().getByPath('carthageBootstrap') - assert subject != null - - subject.commandRunner = commandRunner - } - - def "The carthage bootstrap task should be present"() { - expect: - subject instanceof CarthageBootStrapTask - } - - @Unroll - def "When bootstrap is executed should only update the platform: #platform"() { - given: - commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" - project.xcodebuild.type = platform - - when: - subject.update() - - then: - 1 * commandRunner.run(_, - [CARTHAGE_USR_BIN_PATH, - ACTION_BOOTSTRAP, - ARG_PLATFORM, - carthagePlatform, - ARG_CACHE_BUILDS] - , _ - , _) >> { - args -> args[3] instanceof ConsoleOutputAppender - } - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The task should not be executed if the 'Cartfile` file is missing"() { - given: - commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" - project.xcodebuild.type = platform - - when: - cartFile.delete() - subject.update() - - then: - 0 * commandRunner.run(_, - getCommandRunnerArgsForPlatform(carthagePlatform), - _, - _) >> { - args -> args[3] instanceof ConsoleOutputAppender - } - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The subject output directory should be platform dependant"() { - when: - subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() - project.xcodebuild.type = platform - - then: - Provider outputDirectory = subject.outputDirectory - outputDirectory.isPresent() - outputDirectory.get().name == carthagePlatform - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The xcode selection should be applied if a xcode version is defined"() { - when: - subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() - project.xcodebuild.type = iOS - project.xcodebuild.version = version - - subject.xcode = mockXcode - subject.xcode.setVersionFromString(_) >> _ - subject.update() - - then: - 1 * mockXcode.getXcodeSelectEnvValue(version) - - where: - version | _ - "7.1.1" | _ - } - - private List getCommandRunnerArgsForPlatform(String carthagePlatform) { - return [CARTHAGE_USR_BIN_PATH, - ACTION_UPDATE, - ARG_PLATFORM, - carthagePlatform, - ARG_CACHE_BUILDS] - } -}