From 2f6d65bb30bff7de5b17fd0b641eddbd01852385 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 4 Jun 2018 16:27:45 +0100 Subject: [PATCH 01/36] --wip-- [skip ci] --- build.gradle | 50 +++++++--- .../ExampleOSX.xcodeproj/project.pbxproj | 4 +- .../org/openbakery/CommandRunner.groovy | 6 +- .../org/openbakery/xcode/Xcodebuild.groovy | 12 ++- ...CarthageBootStrapTaskFunctionalTest.groovy | 6 +- .../openbakery/AbstractXcodeBuildTask.groovy | 4 +- .../org/openbakery/InfoPlistModifyTask.groovy | 4 +- .../PrepareXcodeArchivingTask.groovy | 97 ++++++++++++++++--- .../XcodeBuildPluginExtension.groovy | 43 ++++---- .../groovy/org/openbakery/XcodePlugin.groovy | 11 ++- .../org/openbakery/XcodeProjectFile.groovy | 7 +- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 11 +-- .../openbakery/coverage/CoverageTask.groovy | 2 +- .../groovy/org/openbakery/cpd/CpdTask.groovy | 2 +- .../org/openbakery/extension/Signing.groovy | 10 +- .../signing/ProvisioningInstallTask.groovy | 4 +- .../openbakery/signing/SigningMethod.groovy | 1 + .../openbakery/util/VariableResolver.groovy | 4 +- 18 files changed, 183 insertions(+), 95 deletions(-) diff --git a/build.gradle b/build.gradle index 8889fd2a..d403b2a7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,44 @@ -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 +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } } - if (project.hasProperty("buildNumber")) { - versionNumber += "." + project.buildNumber + dependencies { + classpath "org.ajoberstar.reckon:reckon-gradle:0.7.0" } +} + +apply plugin: "org.ajoberstar.reckon" + +reckon { + scopeFromProp() + stageFromProp('snapshot', 'rc', 'final') +} + +reckonTagCreate.dependsOn 'check' +// + +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 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/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index b84bae48..4d2a9f43 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -66,10 +66,9 @@ class Xcodebuild { 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 +79,13 @@ 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] + +// if (xcConfig != null) { +// args.push(ARGUMENT_XCCONFIG) +// args.push(xcConfig.absolutePath) +// } commandRunner.run(args, envMap) } diff --git a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy index ec6a21fc..0587774e 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy @@ -59,7 +59,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { def "The task should be executed with success if a `cartfile.resolved` file is present"() { setup: - testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) when: BuildResult result = gradleRunner.build() @@ -76,7 +76,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { github "ashleymills/Reachability.swift" """ - File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) carthageResolvedFile << """ github "ashleymills/Reachability.swift" "v4.1.0" """ @@ -114,7 +114,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { github "ashleymills/Reachability.swift" """ - File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) carthageResolvedFile << """ github "ashleymills/Reachability.swift" "v4.1.0" """ 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..e75ca53a 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,97 @@ 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(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 207649e8..b68305ca 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -35,6 +35,8 @@ 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() @@ -52,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 @@ -260,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) { @@ -289,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 @@ -303,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) @@ -316,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) @@ -330,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) { @@ -383,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) } @@ -395,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 @@ -416,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 ce142110..d0727015 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -133,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 @@ -488,26 +487,30 @@ 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) } 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) } 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/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/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 +} From 07f9a82de70b046a2e970930985c789304cc6156 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 4 Jun 2018 16:31:26 +0100 Subject: [PATCH 02/36] --wip-- [skip ci] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d403b2a7..20e207be 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ apply plugin: "org.ajoberstar.reckon" reckon { scopeFromProp() - stageFromProp('snapshot', 'rc', 'final') + stageFromProp('dev', 'snapshot', 'rc', 'final') } reckonTagCreate.dependsOn 'check' From 426d56a42abbfaa5e1a592787e0d05560755c276 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 4 Jun 2018 16:33:38 +0100 Subject: [PATCH 03/36] Tweak versioning --- build.gradle | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 20e207be..89610554 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,11 @@ buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } + repositories { jcenter() } dependencies { - classpath "org.ajoberstar.reckon:reckon-gradle:0.7.0" + classpath 'com.netflix.nebula:nebula-release-plugin:6.0.0' } } +apply plugin: 'nebula.release' -apply plugin: "org.ajoberstar.reckon" - -reckon { - scopeFromProp() - stageFromProp('dev', 'snapshot', 'rc', 'final') -} - -reckonTagCreate.dependsOn 'check' // @@ -38,7 +27,7 @@ allprojects { // group = 'org.openbakery' - version = project.version + version = project.version.toString() sourceCompatibility = "1.6" targetCompatibility = "1.6" From 92d5a95a3ceca1556d626904d3e4da5296849905 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 08:34:45 +0100 Subject: [PATCH 04/36] Add reckon back --- build.gradle | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 89610554..ea90633f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,22 @@ buildscript { - repositories { jcenter() } + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } dependencies { - classpath 'com.netflix.nebula:nebula-release-plugin:6.0.0' + classpath "org.ajoberstar.reckon:reckon-gradle:0.7.0" } } -apply plugin: 'nebula.release' +apply plugin: "org.ajoberstar.reckon" + +reckon { + scopeFromProp() + stageFromProp('dev', 'rc', 'final') +} + +reckonTagCreate.dependsOn 'check' // @@ -27,7 +38,7 @@ allprojects { // group = 'org.openbakery' - version = project.version.toString() + version = project.version sourceCompatibility = "1.6" targetCompatibility = "1.6" From 1b4f70ce236e09047a9002ef7f60cc28988baddc Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 08:38:48 +0100 Subject: [PATCH 05/36] Add SNAPSHOT suffix --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ea90633f..e2e1d878 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ allprojects { // group = 'org.openbakery' - version = project.version + version = project.version.toString() + "-SNAPSHOT" sourceCompatibility = "1.6" targetCompatibility = "1.6" From 42bb84e3c559072f774729bbdd2d91e315b30f3c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 15:00:20 +0100 Subject: [PATCH 06/36] Temp fix --- .../main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index e75ca53a..d812e2c2 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -151,6 +151,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { map.put("CODE_SIGN_STYLE", "Manual") 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) { From 1dd6bff7c7308fff02566618a4a52d8bc76b4860 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 15:54:30 +0100 Subject: [PATCH 07/36] Make the packaging xcode version dependant too --- .../org/openbakery/xcode/Xcodebuild.groovy | 26 ++++++++++-------- .../groovy/org/openbakery/XcodePlugin.groovy | 2 ++ .../packaging/PackageTaskIosAndTvOS.groovy | 27 ++++++++++++++++++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index 4d2a9f43..dc6a1243 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -50,17 +50,26 @@ 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, @@ -82,11 +91,6 @@ class Xcodebuild { "-configuration", configuration, ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath] -// if (xcConfig != null) { -// args.push(ARGUMENT_XCCONFIG) -// args.push(xcConfig.absolutePath) -// } - commandRunner.run(args, envMap) } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index d0727015..24e2e2db 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -499,6 +499,8 @@ class XcodePlugin implements Plugin { 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, 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 } } From bc11e1714f6ba08f26aa97edb2901d49cc227003 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 16:02:06 +0100 Subject: [PATCH 08/36] Cleanup --- build.gradle | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/build.gradle b/build.gradle index e2e1d878..1404de0f 100644 --- a/build.gradle +++ b/build.gradle @@ -23,19 +23,6 @@ reckonTagCreate.dependsOn 'check' 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 = project.version.toString() + "-SNAPSHOT" From 587039a424e669a232ced0f8e77087d6cae50262 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 16:05:35 +0100 Subject: [PATCH 09/36] Switch versioning to nebula.release more simple and reliable --- build.gradle | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/build.gradle b/build.gradle index 1404de0f..0fe87927 100644 --- a/build.gradle +++ b/build.gradle @@ -1,23 +1,7 @@ -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "org.ajoberstar.reckon:reckon-gradle:0.7.0" - } +plugins { + id 'nebula.release' version '6.0.0' } -apply plugin: "org.ajoberstar.reckon" - -reckon { - scopeFromProp() - stageFromProp('dev', 'rc', 'final') -} - -reckonTagCreate.dependsOn 'check' - // allprojects { From 9f1c6d8973954981056053de49b428a51e1b8976 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 16:17:13 +0100 Subject: [PATCH 10/36] --wip-- [skip ci] --- build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0fe87927..c519d667 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,10 @@ plugins { id 'nebula.release' version '6.0.0' } +nebulaRelease { + +} + // allprojects { @@ -9,7 +13,7 @@ allprojects { apply plugin: 'groovy' group = 'org.openbakery' - version = project.version.toString() + "-SNAPSHOT" + version = project.version.toString() sourceCompatibility = "1.6" targetCompatibility = "1.6" From 207a9ba3f80f3ffb33f25d8d2eb9aab88c7cee57 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 5 Jun 2018 16:21:50 +0100 Subject: [PATCH 11/36] --wip-- [skip ci] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c519d667..1637be0c 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ allprojects { apply plugin: 'groovy' group = 'org.openbakery' - version = project.version.toString() + version = project.version sourceCompatibility = "1.6" targetCompatibility = "1.6" From 7cc15dcd27f385030ea9a007fd5e7e41d775ef5f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 09:10:39 +0100 Subject: [PATCH 12/36] Simplify versioning via git describe --- build.gradle | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 0fe87927..688b8818 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,22 @@ -plugins { - id 'nebula.release' version '6.0.0' +String getGitDescribeVersion() { + ByteArrayOutputStream output = new ByteArrayOutputStream() + + project.exec({ ExecSpec execSpec -> + execSpec.args = ["describe", "--tags", "--always", "--first-parent"] + execSpec.executable = "git" + execSpec.standardOutput = output + }) + + return output.toString().trim() } // - allprojects { apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' group = 'org.openbakery' - version = project.version.toString() + "-SNAPSHOT" + version = getGitDescribeVersion() + "-SNAPSHOT" sourceCompatibility = "1.6" targetCompatibility = "1.6" From 4fab1e112ac7501d7ec750f9907d3f8144a37484 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 09:34:30 +0100 Subject: [PATCH 13/36] Remove the no more present property --- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 24e2e2db..a20fd2fd 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -499,7 +499,6 @@ class XcodePlugin implements Plugin { 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) } From 7831b6b1e19bc77b60dbd391c3d70f03e81de584 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 09:43:13 +0100 Subject: [PATCH 14/36] No more necessary --- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index a20fd2fd..d0727015 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -499,7 +499,6 @@ class XcodePlugin implements Plugin { it.buildConfiguration.set(xcodeBuildPluginExtension.configuration) it.scheme.set(xcodeBuildPluginExtension.scheme) it.target.set(xcodeBuildPluginExtension.target) - it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, From 115cbcdba84140e2edcb8127798bf88420bc1adb Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 10:22:07 +0100 Subject: [PATCH 15/36] Fix the missing version setter --- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index d0727015..3ce3cf39 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -629,6 +629,7 @@ class XcodePlugin implements Plugin { it.registeredProvisioningFiles.set(signingExtension.registeredProvisioning) it.scheme.set(xcodeBuildPluginExtension.scheme) it.signingMethod.set(signingExtension.signingMethod) + it.xcodeVersion.set(xcodeBuildPluginExtension.version) } } From f14219765a840f83397ca1d90b41073d4772227f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 10:46:50 +0100 Subject: [PATCH 16/36] --wip-- [skip ci] --- .../org/openbakery/carthage/CarthageBootStrapTask.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index 94df3517..6793a7d0 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -94,11 +94,13 @@ class CarthageBootStrapTask extends DefaultTask { @TaskAction void update() { logger.warn('Bootstrap Carthage for platform ' + carthagePlatformName) + println "getDerivedDataFolder().absolutePath : " + getDerivedDataFolder().absolutePath project.exec(new Action() { @Override void execute(ExecSpec execSpec) { execSpec.args = [ACTION_BOOTSTRAP, ARG_CACHE_BUILDS, + "--derived-data", getDerivedDataFolder().absolutePath, "--new-resolver", "--color", "always", ARG_PLATFORM, @@ -111,6 +113,12 @@ class CarthageBootStrapTask extends DefaultTask { }) } + private static File getDerivedDataFolder() { + File result = new File(System.getProperty("java.io.tmpdir"), "carthage-cache") + result.mkdirs() + return result + } + private final Map getEnvValues() { final Map envValues if (requiredXcodeVersion.present) { From 76cfe3c6960eaf991c7412f72e3e2a920fe0f6a2 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 13:23:47 +0100 Subject: [PATCH 17/36] Cleanup --- plugin/src/main/groovy/org/openbakery/extension/Signing.groovy | 1 - .../src/main/groovy/org/openbakery/signing/SigningMethod.groovy | 1 - 2 files changed, 2 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index a3847149..336173c8 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -78,7 +78,6 @@ class Signing { } void setMethod(String method) { - println "setMethod : " + method signingMethod.set(SigningMethod.fromString(method) .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") diff --git a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy index 94efc93c..307710f1 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy @@ -20,7 +20,6 @@ enum SigningMethod { } static Optional fromString(value) { - println "fromString : " + value return Optional.ofNullable(values().find { it.getValue() == value }) } } From 228dc25dc710df18c852e7d46dc99b890307854d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 16:06:53 +0100 Subject: [PATCH 18/36] Test --- .../main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index d812e2c2..99a7ca2c 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -153,6 +153,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) map.put("CODE_SIGN_IDENTITY[sdk=iphoneos*]", certificateFriendlyName.get()) map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) + map.put("PRODUCT_NAME", configurationBundleIdentifier.get().replace(".", "_")) if (provisioningReader.present) { ProvisioningProfileReader reader = provisioningReader.get() From fb4e0960516393feddee70ae3984fd9a3f42448a Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 6 Jun 2018 16:32:45 +0100 Subject: [PATCH 19/36] Revert unwanted changes --- .../main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 99a7ca2c..d812e2c2 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -153,7 +153,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) map.put("CODE_SIGN_IDENTITY[sdk=iphoneos*]", certificateFriendlyName.get()) map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) - map.put("PRODUCT_NAME", configurationBundleIdentifier.get().replace(".", "_")) if (provisioningReader.present) { ProvisioningProfileReader reader = provisioningReader.get() From aa6d96ec83c86ec52bc0b5d44c3e7af8a76cdd10 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 8 Jun 2018 14:09:20 +0100 Subject: [PATCH 20/36] Filter provisioning profiles by target type --- .../codesign/ProvisioningProfileReader.groovy | 3 +++ .../groovy/org/openbakery/XcodePlugin.groovy | 1 + .../org/openbakery/XcodeProjectFile.groovy | 4 ++-- .../signing/ProvisioningFile.groovy | 16 ++++++++++++-- .../signing/ProvisioningInstallTask.groovy | 21 ++++++++++++------- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy index 121b6cc8..2dedab82 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy @@ -149,6 +149,9 @@ class ProvisioningProfileReader { } } + List getPlatforms() { + return config.getProperty("Platform") + } String getUUID() { return config.getString("UUID") diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 3ce3cf39..cd9d50f6 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -585,6 +585,7 @@ class XcodePlugin implements Plugin { ProvisioningInstallTask) { it.group = XCODE_GROUP_NAME + it.buildType.set(xcodeBuildPluginExtension.type) it.commandRunnerProperty.set(commandRunner) it.mobileProvisioningList.set(signingExtension.mobileProvisionList) it.outputDirectory.set(signingExtension.provisioningDestinationRoot) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy index 05ea6f24..6eaedcfc 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy @@ -30,7 +30,6 @@ class XcodeProjectFile { boolean isOSX = false; - XcodeProjectFile(Project project, File projectFile) { this.project = project this.projectFile = projectFile @@ -91,6 +90,7 @@ class XcodeProjectFile { } /* remove this method and update project.xcodebuild settings on the proper places */ + void parse() { this.project.logger.debug("Parse project file: " + projectFile.absolutePath) if (!this.projectFile.exists()) { @@ -156,7 +156,7 @@ class XcodeProjectFile { } - String deviceFamily = getBuildSetting(buildConfiguration, "TARGETED_DEVICE_FAMILY") + String deviceFamily = getBuildSetting(buildConfiguration, "TARGETED_DEVICE_FAMILY") if (deviceFamily == "1") { buildSettings.devices = Devices.PHONE } else if (deviceFamily == "2") { diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy index ee686b80..4619a3b4 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy @@ -1,6 +1,7 @@ package org.openbakery.signing import org.apache.commons.io.FilenameUtils +import org.openbakery.xcode.Type class ProvisioningFile implements Serializable { @@ -10,6 +11,7 @@ class ProvisioningFile implements Serializable { private String teamIdentifier private String teamName private String name + private List platforms public static final String PROVISIONING_NAME_BASE = "gradle-" @@ -18,13 +20,15 @@ class ProvisioningFile implements Serializable { String uuid, String teamIdentifier, String teamName, - String name) { + String name, + List platforms) { this.applicationIdentifier = applicationIdentifier this.file = file this.uuid = uuid this.teamIdentifier = teamIdentifier this.teamName = teamName this.name = name + this.platforms = platforms } String getApplicationIdentifier() { @@ -55,7 +59,15 @@ class ProvisioningFile implements Serializable { return formattedName(uuid, file) } - public static String formattedName(String uuid, File file) { + List getPlatforms() { + return platforms + } + + boolean supportBuildType(Type type) { + return platforms.contains(type.value) + } + + static String formattedName(String uuid, File file) { return PROVISIONING_NAME_BASE + uuid + "." + FilenameUtils.getExtension(file.getName()) } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index ab71ba10..34991203 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -15,10 +15,14 @@ import org.gradle.api.tasks.TaskAction import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PlistHelper +import org.openbakery.xcode.Type @CompileStatic class ProvisioningInstallTask extends Download { + @Input + final Provider buildType = project.objects.property(Type) + @Input final Provider> mobileProvisioningList = project.objects.listProperty(String) @@ -63,11 +67,6 @@ class ProvisioningInstallTask extends Download { this.acceptAnyCertificate(true) } - void registerProvisioning(ProvisioningFile provisioningFile) { - registeredProvisioning.add(provisioningFile.getFile()) - registeredProvisioningFiles.add(provisioningFile) - } - File registerProvisioningInToUserLibrary(ProvisioningFile provisioningFile) { PROVISIONING_DIR.mkdirs() @@ -86,13 +85,20 @@ class ProvisioningInstallTask extends Download { deleteFilesOnExit(files.collect { it.file }) // Register it - files.each(this.®isterProvisioning) + files.findAll { it.supportBuildType(buildType.get()) } + .each(this.®isterProvisioning) // Register into the user library List registeredFiles = files.collect(this.®isterProvisioningInToUserLibrary) deleteFilesOnExit(registeredFiles) } + void registerProvisioning(ProvisioningFile provisioningFile) { + provisioningFile.platforms + registeredProvisioning.add(provisioningFile.getFile()) + registeredProvisioningFiles.add(provisioningFile) + } + File fileFromPath(String path) { return new File(outputDirectory.get().asFile, FilenameUtils.getName(path)) } @@ -111,7 +117,8 @@ class ProvisioningInstallTask extends Download { reader.getUUID(), reader.getTeamIdentifierPrefix(), reader.getTeamName(), - reader.getName()) + reader.getName(), + reader.getPlatforms()) } private List rename() { From 226139a04a74f72f993c11ce58671ccd8bcb1c99 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 12 Jun 2018 14:06:10 +0100 Subject: [PATCH 21/36] --wip-- [skip ci] --- build.gradle | 4 +- .../PrepareXcodeArchivingTask.groovy | 72 +++++++++++------ .../XcodeBuildPluginExtension.groovy | 7 +- .../groovy/org/openbakery/XcodePlugin.groovy | 2 + .../extension/TargetConfiguration.groovy | 23 ++++++ .../org/openbakery/util/SignatureUtil.groovy | 49 ++++++++++++ .../openbakery/util/SignatureUtilTest.groovy | 79 +++++++++++++++++++ 7 files changed, 211 insertions(+), 25 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy create mode 100644 plugin/src/main/groovy/org/openbakery/util/SignatureUtil.groovy create mode 100644 plugin/src/test/groovy/org/openbakery/util/SignatureUtilTest.groovy diff --git a/build.gradle b/build.gradle index 688b8818..92d44577 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,8 @@ allprojects { group = 'org.openbakery' version = getGitDescribeVersion() + "-SNAPSHOT" - sourceCompatibility = "1.6" - targetCompatibility = "1.6" + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 repositories { mavenCentral() diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index d812e2c2..a2d7c1fd 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -9,6 +9,7 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.extension.TargetConfiguration import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper @@ -27,6 +28,9 @@ class PrepareXcodeArchivingTask extends DefaultTask { @InputDirectory final Provider projectFile = newInputFile() + @Input + final ListProperty targetConfigurations = project.objects.listProperty(TargetConfiguration) + final Provider scheme = project.objects.property(String) final Provider buildConfiguration = project.objects.property(String) final Provider target = project.objects.property(String) @@ -112,11 +116,16 @@ class PrepareXcodeArchivingTask extends DefaultTask { } private String findProductId(String rootKey) { + return findProductId(rootKey, target.get()) + } + + private String findProductId(String rootKey, + String targetName) { return getValueFromPbxProjFile("objects:${rootKey}:targets") - .find { it -> getObjectValueFromPbxProjFile("${it}:productName") == target.get() } + .find { it -> getObjectValueFromPbxProjFile("${it}:productName") == targetName } } - private String getBuildConfigurationIdentifier(String targetId) { + private String getBuildConfigurationId(String targetId) { String configurationId = getObjectValueFromPbxProjFile("$targetId:buildConfigurationList") List list = getObjectValueFromPbxProjFile("${configurationId}:buildConfigurations") as List return list.find { @@ -142,31 +151,50 @@ class PrepareXcodeArchivingTask extends DefaultTask { @TaskAction void generate() { - String rootKey = getValueFromPbxProjFile("rootObject") - - String buildConfigurationId = getBuildConfigurationIdentifier(findProductId(rootKey)) - - HashMap map = new HashMap<>() - map.put("CODE_SIGN_STYLE", "Manual") + (targetConfigurations.get() as List) + .each { + println it + configureTargetConfiguration(it) + } - map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) - map.put("CODE_SIGN_IDENTITY[sdk=iphoneos*]", certificateFriendlyName.get()) - map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) +// String rootKey = getValueFromPbxProjFile("rootObject") +// +// String buildConfigurationId = getBuildConfigurationId(findProductId(rootKey)) +// +// HashMap map = new HashMap<>() +// +// map.put("CODE_SIGN_STYLE", "Manual") +// +// map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) +// map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=iphoneos*]", certificateFriendlyName.get()) +// map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=appletvos*]", certificateFriendlyName.get()) +// +// map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) +// +// if (provisioningReader.present) { +// ProvisioningProfileReader reader = provisioningReader.get() +// map.put(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) +// map.put(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) +// map.put(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) +// } +// +// if (entitlementsFile.present) { +// map.put("CODE_SIGN_ENTITLEMENTS", entitlementsFile.get().asFile.absolutePath) +// } +// +// map.each { k, v -> +// setBuildConfigurationBuildSetting(buildConfigurationId, k, v) +// } + } - if (provisioningReader.present) { - ProvisioningProfileReader reader = provisioningReader.get() - map.put(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) - map.put(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) - map.put(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) - } + private void configureTargetConfiguration(TargetConfiguration tc) { + final String rootKey = getValueFromPbxProjFile("rootObject") + String productId = findProductId(rootKey, tc.name) + String buildConfigurationId = getBuildConfigurationId(productId) - if (entitlementsFile.present) { - map.put("CODE_SIGN_ENTITLEMENTS", entitlementsFile.get().asFile.absolutePath) - } + if (tc.certificateFile != null) { - map.each { k, v -> - setBuildConfigurationBuildSetting(buildConfigurationId, k, v) } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index b68305ca..c0d7a936 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -17,6 +17,7 @@ package org.openbakery import org.apache.commons.io.filefilter.SuffixFileFilter import org.apache.commons.lang.StringUtils +import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import org.gradle.api.Transformer import org.gradle.api.file.Directory @@ -24,6 +25,7 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil import org.openbakery.extension.Signing +import org.openbakery.extension.TargetConfiguration import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper import org.openbakery.util.VariableResolver @@ -47,6 +49,7 @@ class XcodeBuildPluginExtension { final DirectoryProperty sharedPrecompsDir = project.layout.directoryProperty() final DirectoryProperty derivedDataPath = project.layout.directoryProperty() final Property xcodeServiceProperty = project.objects.property(XcodeService) + final NamedDomainObjectContainer targetConfigurations final Signing signing @@ -108,8 +111,10 @@ 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) + + targetConfigurations = project.container(TargetConfiguration) + project.extensions.targetConfigurations = targetConfigurations } private void configureServices() { diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index cd9d50f6..e5d7c01d 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -499,6 +499,8 @@ class XcodePlugin implements Plugin { it.buildConfiguration.set(xcodeBuildPluginExtension.configuration) it.scheme.set(xcodeBuildPluginExtension.scheme) it.target.set(xcodeBuildPluginExtension.target) + + it.targetConfigurations.set(xcodeBuildPluginExtension.targetConfigurations) } project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, diff --git a/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy b/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy new file mode 100644 index 00000000..058b1296 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy @@ -0,0 +1,23 @@ +package org.openbakery.extension + +import groovy.transform.CompileStatic + +@CompileStatic +class TargetConfiguration implements Serializable { + + public File provisioningFile + public File certificateFile + public String certificatePassword + public String bundleIdentifier + public File entitlementsFile + + private final String name + + TargetConfiguration(String name) { + this.name = name + } + + String getName() { + return name + } +} diff --git a/plugin/src/main/groovy/org/openbakery/util/SignatureUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/SignatureUtil.groovy new file mode 100644 index 00000000..00f3080f --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/util/SignatureUtil.groovy @@ -0,0 +1,49 @@ +package org.openbakery.util + +import java.util.regex.Matcher +import java.util.regex.Pattern + +class SignatureUtil { + + private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ + + static String getCertificateFriendlyName(File certificateFile, + String certificatePassword) throws RuntimeException { + return Optional.ofNullable(decryptCertificate(certificateFile, certificatePassword) + .split(System.getProperty("line.separator")) + .find { PATTERN.matcher(it).matches() }) + .map { PATTERN.matcher(it) } + .filter { Matcher it -> it.matches() } + .map { Matcher it -> + return it.group("friendlyName") + } + .orElseThrow { + new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") + } + } + + static String decryptCertificate(File certificateFile, + String certificatePassword) throws RuntimeException { + assert certificateFile.exists(): "The certificate file does not exists" + + ProcessBuilder builder = new ProcessBuilder("openssl", + "pkcs12", + "-nokeys", + "-in", certificateFile.absolutePath, + "-passin", "pass:${certificatePassword}") + + builder.redirectOutput() + + final Process process = builder.start() + process.waitFor() + + String result + if (process.exitValue() == 0) { + result = process.getInputStream().text.trim() + } else { + throw new RuntimeException(process.getErrorStream().text.trim()) + } + + return result + } +} diff --git a/plugin/src/test/groovy/org/openbakery/util/SignatureUtilTest.groovy b/plugin/src/test/groovy/org/openbakery/util/SignatureUtilTest.groovy new file mode 100644 index 00000000..80ba6458 --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/util/SignatureUtilTest.groovy @@ -0,0 +1,79 @@ +package org.openbakery.util + +import org.junit.Test +import spock.lang.Specification + +import java.nio.file.Paths + +class SignatureUtilTest extends Specification { + + private File certificateFile = findResource("fake_distribution.p12") + private File fakeFile = Mock(File) + + @Test + def "Should properly resolve the certificate friendly name"() { + when: + String result = SignatureUtil.getCertificateFriendlyName(certificateFile, "p4ssword") + + then: + noExceptionThrown() + + and: + result == "iPhone Distribution: Test Company Name (12345ABCDE)" + } + + @Test + def "Should fail to resolve the certificate friendly name if invalid password"() { + when: + SignatureUtil.getCertificateFriendlyName(certificateFile, "toto") + + then: + RuntimeException exception = thrown RuntimeException + + and: + exception.message == "Mac verify error: invalid password?" + } + + @Test + def "Should properly resolve the content of the certificate file if exists"() { + when: + String result = SignatureUtil.decryptCertificate(certificateFile, "p4ssword") + + then: + noExceptionThrown() + + and: + result.contains("localKeyID: FE 93 19 AC CC D7 C1 AC 82 97 02 C2 35 97 B6 CE 37 33 CB 4F") + } + + @Test + def "Should fail if the certificate password is invalid"() { + when: + SignatureUtil.decryptCertificate(certificateFile, "wrong") + + then: + RuntimeException exception = thrown RuntimeException + exception.message == "Mac verify error: invalid password?" + } + + @Test + def "Should throw an exception is the certificate file does not exists"() { + setup: + + when: + SignatureUtil.decryptCertificate(fakeFile, "p4ssword") + + then: + AssertionError error = thrown AssertionError + error.message.startsWith("The certificate file does not exists") + } + + private File findResource(String name) { + ClassLoader classLoader = getClass().getClassLoader() + return (File) Optional.ofNullable(classLoader.getResource(name)) + .map { URL url -> url.toURI() } + .map { URI uri -> Paths.get(uri).toFile() } + .filter { File file -> file.exists() } + .orElseThrow { new Exception("Resource $name cannot be found") } + } +} From 0c25ed2a433aaffcd73be8a4052fcd48db34d948 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 13 Jun 2018 13:49:33 +0100 Subject: [PATCH 22/36] - Refactoring the executaiton of XcodeBuildArchiveTaskIosAndTvOS.groovy class - Now PrepareXcodeArchivingTask.groovy apply to all configurations --- .../org/openbakery/xcode/Xcodebuild.groovy | 1 + .../PrepareXcodeArchivingTask.groovy | 79 +++++++++++-------- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 24 ++++-- 3 files changed, 62 insertions(+), 42 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index dc6a1243..d25532a7 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -19,6 +19,7 @@ class Xcodebuild { public static final String EXECUTABLE = "xcodebuild" public static final String ACTION_ARCHIVE = "archive" public static final String ACTION_EXPORT_ARCHIVE = "-exportArchive" + public static final String ARGUMENT_CONFIGURATION = "-configuration" public static final String ARGUMENT_SCHEME = "-scheme" public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" public static final String ARGUMENT_EXPORT_PATH = "-exportPath" diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index a2d7c1fd..dda34c5a 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -14,6 +14,7 @@ import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper +import org.openbakery.util.SignatureUtil @CompileStatic class PrepareXcodeArchivingTask extends DefaultTask { @@ -151,50 +152,58 @@ class PrepareXcodeArchivingTask extends DefaultTask { @TaskAction void generate() { - (targetConfigurations.get() as List) .each { - println it configureTargetConfiguration(it) } - -// String rootKey = getValueFromPbxProjFile("rootObject") -// -// String buildConfigurationId = getBuildConfigurationId(findProductId(rootKey)) -// -// HashMap map = new HashMap<>() -// -// map.put("CODE_SIGN_STYLE", "Manual") -// -// map.put(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) -// map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=iphoneos*]", certificateFriendlyName.get()) -// map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=appletvos*]", certificateFriendlyName.get()) -// -// map.put(KEY_BUNDLE_IDENTIFIER, configurationBundleIdentifier.get()) -// -// if (provisioningReader.present) { -// ProvisioningProfileReader reader = provisioningReader.get() -// map.put(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) -// map.put(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) -// map.put(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) -// } -// -// if (entitlementsFile.present) { -// map.put("CODE_SIGN_ENTITLEMENTS", entitlementsFile.get().asFile.absolutePath) -// } -// -// map.each { k, v -> -// setBuildConfigurationBuildSetting(buildConfigurationId, k, v) -// } } private void configureTargetConfiguration(TargetConfiguration tc) { - final String rootKey = getValueFromPbxProjFile("rootObject") - String productId = findProductId(rootKey, tc.name) - String buildConfigurationId = getBuildConfigurationId(productId) + HashMap map = new HashMap<>() + configureSignature(map, tc) + configureProvisioning(map, tc) + configureEntitlements(map, tc) + + final String buildConfigurationId = getBuildConfigurationId(findProductId( + getValueFromPbxProjFile("rootObject") as String, + tc.name)) + + map.each { k, v -> + setBuildConfigurationBuildSetting(buildConfigurationId, k, v) + } + } + + private void configureSignature(HashMap map, + TargetConfiguration tc) { + if (tc.certificateFile != null && tc.certificateFile.exists()) { + String friendlyName = SignatureUtil.getCertificateFriendlyName(tc.certificateFile, + tc.certificatePassword) + + map.put(KEY_CODE_SIGN_IDENTITY, friendlyName) + map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=iphoneos*]", friendlyName) + map.put(KEY_CODE_SIGN_IDENTITY + "[sdk=appletvos*]", friendlyName) + } + + map.put("CODE_SIGN_STYLE", "Manual") + } + + private void configureProvisioning(HashMap map, + TargetConfiguration tc) { + if (tc.provisioningFile != null) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(tc.provisioningFile, + commandRunnerProperty.get()) + + map.put(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) + map.put(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) + map.put(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) + } + } - if (tc.certificateFile != null) { + private void configureEntitlements(HashMap map, + TargetConfiguration tc) { + if (tc.entitlementsFile != null) { + map.put(KEY_CODE_SIGN_ENTITLEMENTS, tc.entitlementsFile.absolutePath) } } diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 142046c2..a7897cd9 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,13 +1,13 @@ package org.openbakery.archiving import groovy.transform.CompileStatic -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.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec +import org.gradle.api.tasks.Exec import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction @@ -20,7 +20,7 @@ import org.openbakery.xcode.Xcode import org.openbakery.xcode.Xcodebuild @CompileStatic -class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { +class XcodeBuildArchiveTaskIosAndTvOS extends Exec { @Input final Provider xcodeVersion = project.objects.property(String) @@ -56,6 +56,9 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { return buildType.get() == Type.iOS || buildType.get() == Type.tvOS } }) + + setExecutable("xcodebuild") + setWorkingDir(project.rootProject.rootDir) } @TaskAction @@ -69,11 +72,18 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { "\n\tScheme : ${scheme.get()} " + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}") - Xcodebuild.archive(commandRunnerProperty.get(), - scheme.get(), - outputArchiveFile.get().asFile, - buildConfiguration.get(), - getXcodeAppForConfiguration().getOrNull()) + args(Xcodebuild.ACTION_ARCHIVE, + Xcodebuild.ARGUMENT_SCHEME, scheme.get(), + Xcodebuild.ARGUMENT_CONFIGURATION, buildConfiguration.get(), + Xcodebuild.ARGUMENT_ARCHIVE_PATH, outputArchiveFile.get().asFile.absolutePath) + + if (getXcodeAppForConfiguration().present) { + HashMap map = new HashMap<>() + map.put(Xcode.ENV_DEVELOPER_DIR, getXcodeAppForConfiguration().present ? getXcodeAppForConfiguration().get().absolutePath : null) + setEnvironment(map) + } + + super.exec() } private Provider getXcodeAppForConfiguration() { From 37beff4e6a01caa835f563f1cda608ee8f9a21d6 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 13 Jun 2018 17:55:48 +0100 Subject: [PATCH 23/36] Make it verbose for now --- .../openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index a7897cd9..25b6eb20 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -68,7 +68,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends Exec { outputArchiveFile.get().asFile.parentFile.mkdirs() - logger.lifecycle("Archive project with configuration: " + + println("Archive project with configuration: " + "\n\tScheme : ${scheme.get()} " + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}") From c7fc4e65572bd60fde95dbb876f6c01467e95c0e Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 13 Jun 2018 18:09:27 +0100 Subject: [PATCH 24/36] Specify the working dir --- .../openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 25b6eb20..7de1c25a 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -83,6 +83,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends Exec { setEnvironment(map) } + setWorkingDir(project.rootProject.rootDir) + super.exec() } From 7d037a6fc9f936cacb701bb7f8d79ee5e7efde07 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 14 Jun 2018 11:08:21 +0100 Subject: [PATCH 25/36] - Replace exec with ProcessBuilder - Explose the configuration for more clarity - Add some verbosing - Output the build logs into a separated output file --- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 7de1c25a..16f8889a 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,13 +1,13 @@ package org.openbakery.archiving import groovy.transform.CompileStatic +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.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec -import org.gradle.api.tasks.Exec import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction @@ -20,7 +20,7 @@ import org.openbakery.xcode.Xcode import org.openbakery.xcode.Xcodebuild @CompileStatic -class XcodeBuildArchiveTaskIosAndTvOS extends Exec { +class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { @Input final Provider xcodeVersion = project.objects.property(String) @@ -56,36 +56,51 @@ class XcodeBuildArchiveTaskIosAndTvOS extends Exec { return buildType.get() == Type.iOS || buildType.get() == Type.tvOS } }) - - setExecutable("xcodebuild") - setWorkingDir(project.rootProject.rootDir) } @TaskAction void archive() { - assert scheme.present: "No target scheme configured" - assert outputArchiveFile.present: "No output file folder configured" + logger.info("Archive project with configuration: " + + "\n\tScheme : ${scheme.getOrNull()} " + + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}" + + "\n\tBuild configuration : ${buildConfiguration.getOrNull()}") - outputArchiveFile.get().asFile.parentFile.mkdirs() + final Process process = configureProcessBuilder().start() + process.waitFor() - println("Archive project with configuration: " + - "\n\tScheme : ${scheme.get()} " + - "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}") + if (process.exitValue() != 0) { + throw new RuntimeException(process.errorStream.getText()) + } + } - args(Xcodebuild.ACTION_ARCHIVE, + private ProcessBuilder configureProcessBuilder() { + assert scheme.present: "No target scheme configured" + assert buildConfiguration.present: "No build configuration configured" + assert outputArchiveFile.present: "No output file folder configured" + + ProcessBuilder builder = new ProcessBuilder("xcodebuild", + Xcodebuild.ACTION_ARCHIVE, Xcodebuild.ARGUMENT_SCHEME, scheme.get(), Xcodebuild.ARGUMENT_CONFIGURATION, buildConfiguration.get(), Xcodebuild.ARGUMENT_ARCHIVE_PATH, outputArchiveFile.get().asFile.absolutePath) if (getXcodeAppForConfiguration().present) { - HashMap map = new HashMap<>() - map.put(Xcode.ENV_DEVELOPER_DIR, getXcodeAppForConfiguration().present ? getXcodeAppForConfiguration().get().absolutePath : null) - setEnvironment(map) + builder.environment().put(Xcode.ENV_DEVELOPER_DIR, + getXcodeAppForConfiguration().map { it.absolutePath }.get() as String) } - setWorkingDir(project.rootProject.rootDir) - super.exec() + builder.redirectOutput(configureLogOutputFile()) + return builder + } + + private File configureLogOutputFile() { + File file = project.layout + .buildDirectory + .file("archiving_output.log").get().asFile + + logger.info("Build log located here : ", file.path) + return file } private Provider getXcodeAppForConfiguration() { From 21b98a962299a2bbf87150f716d0df3b8c4f6e82 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 14 Jun 2018 12:20:49 +0100 Subject: [PATCH 26/36] - Fix the buid type property to use the proper lazy value --- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index e5d7c01d..bceb248d 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -587,7 +587,7 @@ class XcodePlugin implements Plugin { ProvisioningInstallTask) { it.group = XCODE_GROUP_NAME - it.buildType.set(xcodeBuildPluginExtension.type) + it.buildType.set(xcodeBuildPluginExtension.targetType) it.commandRunnerProperty.set(commandRunner) it.mobileProvisioningList.set(signingExtension.mobileProvisionList) it.outputDirectory.set(signingExtension.provisioningDestinationRoot) From 8bcd0352e74c718fde435e474be40357de5d0c35 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 14 Jun 2018 12:55:37 +0100 Subject: [PATCH 27/36] - Describe the build folder for the archiving task --- .../openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 16f8889a..0bbc08e5 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -84,6 +84,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { Xcodebuild.ARGUMENT_CONFIGURATION, buildConfiguration.get(), Xcodebuild.ARGUMENT_ARCHIVE_PATH, outputArchiveFile.get().asFile.absolutePath) + builder.directory(project.rootProject.rootDir) + if (getXcodeAppForConfiguration().present) { builder.environment().put(Xcode.ENV_DEVELOPER_DIR, getXcodeAppForConfiguration().map { it.absolutePath }.get() as String) From 4e768f12e71555818a06e87ba55f52d978be5866 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 14 Jun 2018 14:41:04 +0100 Subject: [PATCH 28/36] - Remove the local resolution of the signature friendly name - In replacement use the implementation - It avoid at the same time to display in verbose mode the content of the key for security perspective --- .../signing/KeychainCreateTask.groovy | 38 ++----------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 51d46b5b..7f1567d1 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -11,10 +11,10 @@ import org.openbakery.CommandRunner import org.openbakery.CommandRunnerException import org.openbakery.codesign.Security import org.openbakery.util.FileUtil +import org.openbakery.util.SignatureUtil import org.openbakery.util.SystemUtil import org.openbakery.xcode.Version -import java.util.regex.Matcher import java.util.regex.Pattern @CompileStatic @@ -110,7 +110,8 @@ class KeychainCreateTask extends Download { } private void parseCertificateFile() { - certificateFriendlyName.set(getSignatureFriendlyName()) + certificateFriendlyName.set(SignatureUtil.getCertificateFriendlyName(temporaryCertificateFile, + certificatePassword.get())) // Delete on exit the downloaded files project.gradle.buildFinished { @@ -196,37 +197,4 @@ class KeychainCreateTask extends Download { logger.info("The temporary keychain has been removed from the search list") } } - - String getSignatureFriendlyName() { - return java.util.Optional.ofNullable(getKeyContent(temporaryCertificateFile) - .split(System.getProperty("line.separator")) - .find { PATTERN.matcher(it).matches() }) - .map { PATTERN.matcher(it) } - .filter { Matcher it -> it.matches() } - .map { Matcher it -> - return it.group("friendlyName") - } - .orElseThrow { - new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") - } - } - - private String getKeyContent(File file) { - String result - try { - result = commandRunnerProperty.get() - .runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + certificatePassword.get()]) - } catch (CommandRunnerException exception) { - logger.warn(exception.toString()) - result = null - } - - return result - } } From d8dbef98bc3498bad803821a7f4e88f1a53b6a85 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 19 Jun 2018 12:20:01 +0100 Subject: [PATCH 29/36] - Create a FunctionalTestBase base class to simplify boilerplate for functional test classes - Update and fix several function test to fix issues post changes --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../org/openbakery/FunctionalTestBase.groovy | 55 +++++ .../KeychainCreateTaskFunctionalTest.groovy | 28 +-- .../PackageTaskIosAndTvOSTest.groovy | 28 +-- ...PrepareXcodeArchivingFunctionalTest.groovy | 193 ------------------ ...CarthageBootStrapTaskFunctionalTest.groovy | 31 +-- ...ovisioningInstallTaskFunctionalTest.groovy | 38 +--- .../resources/test1.mobileprovision | 6 +- .../PrepareXcodeArchivingTask.groovy | 11 +- .../XcodeBuildPluginExtension.groovy | 8 +- .../groovy/org/openbakery/XcodePlugin.groovy | 1 - .../org/openbakery/XcodeProjectFile.groovy | 4 + .../signing/KeychainCreateTask.groovy | 5 - .../PrepareXcodeArchivingTaskTest.groovy | 96 --------- 14 files changed, 91 insertions(+), 415 deletions(-) create mode 100644 plugin/src/functionalTest/groovy/org/openbakery/FunctionalTestBase.groovy delete mode 100644 plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy delete mode 100644 plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ea720f98..9d2dc020 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip diff --git a/plugin/src/functionalTest/groovy/org/openbakery/FunctionalTestBase.groovy b/plugin/src/functionalTest/groovy/org/openbakery/FunctionalTestBase.groovy new file mode 100644 index 00000000..f2d5862b --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/FunctionalTestBase.groovy @@ -0,0 +1,55 @@ +package org.openbakery + +import org.apache.commons.io.FileUtils +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class FunctionalTestBase extends Specification { + + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + List pluginClasspath + + File buildFile + + void genericSetup() { + extractPluginClassPathResource() + createMockBuildFile() + copyTestProject() + } + + void extractPluginClassPathResource() { + URL 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) } + } + + void createMockBuildFile() { + buildFile = testProjectDir.newFile('build.gradle') + buildFile << """ + plugins { + id 'org.openbakery.xcode-plugin' + } + """ + } + + void copyTestProject() { + URL folder = getClass().classLoader + .findResource("TestProject") + + + File file = new File(folder.getFile()) + assert file.exists() + + FileUtils.copyDirectory(file, testProjectDir.root) + } +} diff --git a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy index 71b02662..ce4c7f5c 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy @@ -3,43 +3,23 @@ package org.openbakery 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 org.openbakery.signing.KeychainCreateTask import spock.lang.Shared -import spock.lang.Specification import java.nio.file.Paths -class KeychainCreateTaskFunctionalTest extends Specification { - - @Rule - final TemporaryFolder testProjectDir = new TemporaryFolder() - - List pluginClasspath +class KeychainCreateTaskFunctionalTest extends FunctionalTestBase { @Shared File certificate - File buildFile - def setup() { - 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) } + extractPluginClassPathResource() + createMockBuildFile() + copyTestProject() certificate = findResource("fake_distribution.p12") assert certificate.exists() - - buildFile = testProjectDir.newFile('build.gradle') - buildFile << """ - plugins { - id 'org.openbakery.xcode-plugin' - } - """ } def "The task list should contain the task"() { diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy index 83c7d69b..5c8b563c 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy @@ -1,39 +1,15 @@ package org.openbakery import org.gradle.testkit.runner.GradleRunner -import org.junit.Rule -import org.junit.rules.TemporaryFolder import org.openbakery.packaging.PackageTaskIosAndTvOS -import spock.lang.Specification -class PackageTaskIosAndTvOSTest extends Specification { - - @Rule - final TemporaryFolder testProjectDir = new TemporaryFolder() - - List pluginClasspath - - File buildFile +class PackageTaskIosAndTvOSTest extends FunctionalTestBase { def setup() { - buildFile = testProjectDir.newFile('build.gradle') - - 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) } + genericSetup() } def "The task list should contain the task"() { - given: - buildFile << """ - plugins { - id 'org.openbakery.xcode-plugin' - } - """ - when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy deleted file mode 100644 index f1606a6d..00000000 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ /dev/null @@ -1,193 +0,0 @@ -package org.openbakery - -import org.apache.commons.io.FileUtils -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 org.openbakery.util.PathHelper -import spock.lang.Specification - -import java.nio.file.Paths - -class PrepareXcodeArchivingFunctionalTest extends Specification { - - @Rule - final TemporaryFolder testProjectDir = new TemporaryFolder() - - List pluginClasspath - - File buildFile - - - File provisioningFileWildCard - - def setup() { - pluginClasspath = findResource("plugin-classpath.txt") - .readLines() - .collect { new File(it) } - - FileUtils.copyDirectory(findResource("TestProject"), testProjectDir.getRoot()) - - provisioningFileWildCard = findResource("test1.mobileprovision") - } - - def setupBuildFile() { - buildFile = testProjectDir.newFile('build.gradle') - buildFile << """ - plugins { - id 'org.openbakery.xcode-plugin' - } - - xcodebuild { - target = 'TestProject' - scheme = "TestScheme" - signing { - mobileProvisionURI = "${provisioningFileWildCard.toURI().toString()}" - } - } - - """ - } - - def "The task list should contain the task"() { - given: - setupBuildFile() - - when: - def result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments('tasks') - .withPluginClasspath(pluginClasspath) - .build() - - then: - result.output.contains(PrepareXcodeArchivingTask.NAME - + " - " - + PrepareXcodeArchivingTask.DESCRIPTION) - } - - def "The task should complete without error and generate the xcconfig file"() { - setup: - setupBuildFile() - - when: - buildFile << """ - xcodebuild { - infoplist { - bundleIdentifier = "org.openbakery.test.ExampleWidget" - } - } - """ - - final File certificate = findResource("fake_distribution.p12") - assert certificate.exists() - buildFile << """ - xcodebuild { - infoplist { - bundleIdentifier = "org.openbakery.test.ExampleWidget" - } - - signing { - certificateURI = "${certificate.toURI().toString()}" - certificatePassword = "p4ssword" - } - } - """ - - BuildResult result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments(PrepareXcodeArchivingTask.NAME) - .withPluginClasspath(pluginClasspath) - .build() - - then: "The task should complete without error" - - result.task(":" + PrepareXcodeArchivingTask.NAME) - .outcome == TaskOutcome.SUCCESS - - and: "The archive xcconfig provisioningFile1 should be properly generated and populated from configured values" - - File outputFile = new File(testProjectDir.root, "build/" - + PathHelper.FOLDER_ARCHIVE - + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME) - - outputFile.exists() - - String text = outputFile.text - text.contains("PRODUCT_BUNDLE_IDENTIFIER = org.openbakery.test.ExampleWidget") - text.contains("iPhone Distribution: Test Company Name (12345ABCDE)") - text.contains("PROVISIONING_PROFILE = XXXXFFFF-AAAA-BBBB-CCCC-DDDDEEEEFFFF") - text.contains("PROVISIONING_PROFILE_SPECIFIER = ad hoc") - text.contains("DEVELOPMENT_TEAM = XXXYYYZZZZ") - - and: "Should no contain any entitlements information" - !text.contains("CODE_SIGN_ENTITLEMENTS =") - } - - def "If present the entitlements file should be present into the xcconfig file"() { - setup: - setupBuildFile() - - when: - buildFile << """ - xcodebuild { - infoplist { - bundleIdentifier = "org.openbakery.test.ExampleWidget" - } - } - """ - - final File certificate = findResource("fake_distribution.p12") - assert certificate.exists() - - final File entitlementsFile = findResource("fake.entitlements") - assert entitlementsFile.exists() - - buildFile << """ - xcodebuild { - infoplist { - bundleIdentifier = "org.openbakery.test.ExampleWidget" - } - - signing { - certificateURI = "${certificate.toURI().toString()}" - certificatePassword = "p4ssword" - entitlementsFile = "${entitlementsFile.absolutePath}" - } - } - """ - - BuildResult result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments(PrepareXcodeArchivingTask.NAME) - .withPluginClasspath(pluginClasspath) - .build() - - then: "The task should complete without error" - - result.task(":" + PrepareXcodeArchivingTask.NAME) - .outcome == TaskOutcome.SUCCESS - - and: "The archive xcconfig should contains the path to the entitlements provisioningFile1" - - File outputFile = new File(testProjectDir.root, "build/" - + PathHelper.FOLDER_ARCHIVE - + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME) - - outputFile.exists() - - String text = outputFile.text - text.contains("CODE_SIGN_ENTITLEMENTS = ${entitlementsFile.absolutePath}") - } - - private File findResource(String name) { - ClassLoader classLoader = getClass().getClassLoader() - return (File) Optional.ofNullable(classLoader.getResource(name)) - .map { URL url -> url.toURI() } - .map { URI uri -> Paths.get(uri).toFile() } - .filter { File file -> file.exists() } - .orElseThrow { new Exception("Resource $name cannot be found") } - } -} diff --git a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy index 0587774e..a3e120da 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy @@ -3,34 +3,15 @@ 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 +import org.openbakery.FunctionalTestBase -class CarthageBootStrapTaskFunctionalTest extends Specification { - @Rule - final TemporaryFolder testProjectDir = new TemporaryFolder() +class CarthageBootStrapTaskFunctionalTest extends FunctionalTestBase { - 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) } + genericSetup() gradleRunner = GradleRunner.create() .withProjectDir(testProjectDir.root) @@ -59,7 +40,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { def "The task should be executed with success if a `cartfile.resolved` file is present"() { setup: - testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) when: BuildResult result = gradleRunner.build() @@ -76,7 +57,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { github "ashleymills/Reachability.swift" """ - File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) carthageResolvedFile << """ github "ashleymills/Reachability.swift" "v4.1.0" """ @@ -114,7 +95,7 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { github "ashleymills/Reachability.swift" """ - File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_RESOLVED_FILE) + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) carthageResolvedFile << """ github "ashleymills/Reachability.swift" "v4.1.0" """ diff --git a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy index 16dce6f6..79621157 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy @@ -2,50 +2,28 @@ package org.openbakery.signing 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 +import org.openbakery.FunctionalTestBase import spock.lang.Unroll import java.nio.file.Paths -class ProvisioningInstallTaskFunctionalTest extends Specification { - @Rule - final TemporaryFolder testProjectDir = new TemporaryFolder() +class ProvisioningInstallTaskFunctionalTest extends FunctionalTestBase { - List pluginClasspath - - File buildFile File provisioningFile1 def setup() { - buildFile = testProjectDir.newFile('build.gradle') - - buildFile << """ - plugins { - id 'org.openbakery.xcode-plugin' - } - """ - + genericSetup() provisioningFile1 = findResource("test1.mobileprovision") assert provisioningFile1.exists() - - 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) } } def "The task list should contain the task"() { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('tasks') + .withArguments('tasks', '--s') .withPluginClasspath(pluginClasspath) + .withDebug(true) .build() then: @@ -102,7 +80,7 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments(ProvisioningInstallTask.TASK_NAME) + .withArguments(ProvisioningInstallTask.TASK_NAME, "--s") .withPluginClasspath(pluginClasspath) .withDebug(true) .build() @@ -141,10 +119,8 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { where: gradleVersion | _ - "4.4" | _ - "4.5" | _ - "4.6" | _ "4.7" | _ + "4.8" | _ } private File findResource(String name) { diff --git a/plugin/src/functionalTest/resources/test1.mobileprovision b/plugin/src/functionalTest/resources/test1.mobileprovision index d8fded0c..2435aef5 100644 --- a/plugin/src/functionalTest/resources/test1.mobileprovision +++ b/plugin/src/functionalTest/resources/test1.mobileprovision @@ -42,5 +42,9 @@ XXXYYYZZZZ + Platform + + iOS + - \ No newline at end of file + diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index dda34c5a..63f8e2b0 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -10,8 +10,6 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.extension.TargetConfiguration -import org.openbakery.signing.KeychainCreateTask -import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper import org.openbakery.util.SignatureUtil @@ -32,7 +30,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { @Input final ListProperty targetConfigurations = project.objects.listProperty(TargetConfiguration) - final Provider scheme = project.objects.property(String) final Provider buildConfiguration = project.objects.property(String) final Provider target = project.objects.property(String) @@ -50,7 +47,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" - static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" static final String KEY_CODE_SIGN_ENTITLEMENTS = "CODE_SIGN_ENTITLEMENTS" static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" @@ -59,12 +55,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { PrepareXcodeArchivingTask() { super() - - dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) - dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) - dependsOn(KeychainCreateTask.TASK_NAME) - dependsOn(ProvisioningInstallTask.TASK_NAME) - + this.description = DESCRIPTION this.entitlementsFilePath.set(entitlementsFile.map(new Transformer() { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index c0d7a936..a20f8997 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -401,12 +401,16 @@ class XcodeBuildPluginExtension { return this.projectFile } - String[] projectFiles = project.rootProject.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.rootProject.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 diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index bceb248d..c7409edd 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -497,7 +497,6 @@ class XcodePlugin implements Plugin { it.registeredProvisioningFiles.set(signingExtension.registeredProvisioningFiles) it.buildConfiguration.set(xcodeBuildPluginExtension.configuration) - it.scheme.set(xcodeBuildPluginExtension.scheme) it.target.set(xcodeBuildPluginExtension.target) it.targetConfigurations.set(xcodeBuildPluginExtension.targetConfigurations) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy index 6eaedcfc..f55cb5a6 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeProjectFile.groovy @@ -101,6 +101,10 @@ class XcodeProjectFile { throw new IllegalArgumentException("'xcodebuild.target' is null"); } + if (!project.xcodebuild.configuration.present) { + throw new IllegalArgumentException("'xcodebuild.configuration' is not defined"); + } + BuildConfiguration settings = getBuildConfiguration(project.xcodebuild.target.get(), project.xcodebuild.configuration.get()) logger.debug("rootObjectKey {}", rootObjectKey); verifyTarget(project.xcodebuild.target.get()) diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 7f1567d1..1a9c99b3 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -8,15 +8,12 @@ import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.openbakery.CommandRunner -import org.openbakery.CommandRunnerException import org.openbakery.codesign.Security import org.openbakery.util.FileUtil import org.openbakery.util.SignatureUtil import org.openbakery.util.SystemUtil import org.openbakery.xcode.Version -import java.util.regex.Pattern - @CompileStatic class KeychainCreateTask extends Download { @@ -44,8 +41,6 @@ class KeychainCreateTask extends Download { final Property security = project.objects.property(Security) final DirectoryProperty outputDirectory = newOutputDirectory() - private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ - static final String TASK_NAME = "keychainCreate" static final String TASK_DESCRIPTION = "Create a keychain that is used for signing the app" static final String KEYCHAIN_DEFAULT_PASSWORD = "This_is_the_default_keychain_password" diff --git a/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy deleted file mode 100644 index 8efa86c0..00000000 --- a/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy +++ /dev/null @@ -1,96 +0,0 @@ -package org.openbakery - -import org.gradle.api.Project -import org.gradle.testfixtures.ProjectBuilder -import org.junit.Rule -import org.junit.rules.TemporaryFolder -import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.extension.Signing -import org.openbakery.util.PlistHelper -import spock.lang.Specification - -import static org.openbakery.PrepareXcodeArchivingTask.* - -class PrepareXcodeArchivingTaskTest extends Specification { - - PrepareXcodeArchivingTask subject - Signing signing - Project project - File outputFile - File entitlementsFile - - CommandRunner commandRunner = Mock(CommandRunner) - ProvisioningProfileReader provisioningProfileReader = Mock(ProvisioningProfileReader) - PlistHelper plistHelper = Mock(PlistHelper) - - private static final String FAKE_TEAM_ID = "Team Identifier" - private static final String FAKE_BUNDLE_IDENTIFIER = "co.test.test" - private static final String FAKE_FRIENDLY_NAME = "Fake Certificate FriendlyName (12345)" - private static final String FAKE_UUID = "FAKE_UUID" - private static final String FAKE_PROV_NAME = "Provisioning Name" - - @Rule - final TemporaryFolder tmpDirectory = new TemporaryFolder() - - def setup() { - this.project = ProjectBuilder.builder().withProjectDir(tmpDirectory.root).build() - this.project.apply plugin: XcodePlugin - - this.entitlementsFile = tmpDirectory.newFile("test.entitlements") - this.outputFile = tmpDirectory.newFile("test.xcconfig") - this.signing = project.extensions.findByType(Signing) - - configureSubject() - - provisioningProfileReader.getTeamIdentifierPrefix() >> FAKE_TEAM_ID - provisioningProfileReader.getUUID() >> FAKE_UUID - provisioningProfileReader.getName() >> FAKE_PROV_NAME - } - - def configureSubject() { - subject = project.tasks.findByName(NAME) as PrepareXcodeArchivingTask - subject.certificateFriendlyName.set(FAKE_FRIENDLY_NAME) - subject.commandRunnerProperty.set(commandRunner) - subject.configurationBundleIdentifier.set(FAKE_BUNDLE_IDENTIFIER) - subject.outputFile.set(outputFile) - subject.plistHelperProperty.set(plistHelper) - subject.provisioningReader.set(provisioningProfileReader) - } - - def "The generation should be executed without exception"() { - when: - subject.generate() - - then: - noExceptionThrown() - - and: "The generate file content should be valid" - String text = outputFile.text - text.contains("${KEY_CODE_SIGN_IDENTITY} = ${FAKE_FRIENDLY_NAME}") - text.contains("${KEY_DEVELOPMENT_TEAM} = ${FAKE_TEAM_ID}") - text.contains("${KEY_PROVISIONING_PROFILE_ID} = ${FAKE_UUID}") - text.contains("${KEY_PROVISIONING_PROFILE_SPEC} = ${FAKE_PROV_NAME}") - - and: "And no entitlements information should be present" - !text.contains("${KEY_CODE_SIGN_ENTITLEMENTS} = ") - } - - def "The generate file should refer the entitlements file is present"() { - when: - subject.entitlementsFile.set(entitlementsFile) - subject.generate() - - then: - noExceptionThrown() - - and: - String text = outputFile.text - text.contains("${KEY_CODE_SIGN_IDENTITY} = ${FAKE_FRIENDLY_NAME}") - text.contains("${KEY_DEVELOPMENT_TEAM} = ${FAKE_TEAM_ID}") - text.contains("${KEY_PROVISIONING_PROFILE_ID} = ${FAKE_UUID}") - text.contains("${KEY_PROVISIONING_PROFILE_SPEC} = ${FAKE_PROV_NAME}") - - and: "No entitlements information should be present" - text.contains("${KEY_CODE_SIGN_ENTITLEMENTS} = ${entitlementsFile.absolutePath}") - } -} From dd0033e2a5216a9adbfab4ea389e9ca29c9926f1 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Jul 2018 11:50:50 +0100 Subject: [PATCH 30/36] Now allow to change the bundle identifier of the targert The `BUNDLE_ID` property is now being applied if the targetconfiguration has the value. --- .../org/openbakery/PrepareXcodeArchivingTask.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 63f8e2b0..aff83876 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -154,6 +154,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { configureSignature(map, tc) configureProvisioning(map, tc) configureEntitlements(map, tc) + configureInfoPlist(map, tc) final String buildConfigurationId = getBuildConfigurationId(findProductId( getValueFromPbxProjFile("rootObject") as String, @@ -198,6 +199,13 @@ class PrepareXcodeArchivingTask extends DefaultTask { } } + private void configureInfoPlist(HashMap map, + TargetConfiguration tc) { + if (tc.bundleIdentifier != null) { + map.put("BUNDLE_ID", tc.bundleIdentifier) + } + } + private File toXml(File source) { File file = File.createTempFile("project.plist", "") commandRunnerProperty.get() From e773d1873c2f50654c63c582a7533605503e43a6 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Jul 2018 14:06:12 +0100 Subject: [PATCH 31/36] Add more traces for clarity --- .../groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index aff83876..1cea3a42 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -88,6 +88,9 @@ class PrepareXcodeArchivingTask extends DefaultTask { .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) this.onlyIf { + println "provisioningForConfiguration : " + provisioningForConfiguration + println "configurationBundleIdentifier : " + configurationBundleIdentifier + println "certificateFriendlyName : " + certificateFriendlyName return certificateFriendlyName.present && configurationBundleIdentifier.present && provisioningForConfiguration.present @@ -135,7 +138,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { plistHelperProperty.get() .addValueForPlist(getPbxProjFile(), completeKey, value) } else { - plistHelperProperty.get() .setValueForPlist(getPbxProjFile(), completeKey, value) } From c4421cc43be2bb61125dce6b1852cd9cec7911ad Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Jul 2018 14:44:23 +0100 Subject: [PATCH 32/36] Disable the onlyIf check for now --- .../org/openbakery/PrepareXcodeArchivingTask.groovy | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 1cea3a42..e6a2e6be 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -55,7 +55,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { PrepareXcodeArchivingTask() { super() - + this.description = DESCRIPTION this.entitlementsFilePath.set(entitlementsFile.map(new Transformer() { @@ -86,15 +86,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { this.outputFile.set(project.layout .buildDirectory .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) - - this.onlyIf { - println "provisioningForConfiguration : " + provisioningForConfiguration - println "configurationBundleIdentifier : " + configurationBundleIdentifier - println "certificateFriendlyName : " + certificateFriendlyName - return certificateFriendlyName.present && - configurationBundleIdentifier.present && - provisioningForConfiguration.present - } } private File getPbxProjFile() { @@ -138,6 +129,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { plistHelperProperty.get() .addValueForPlist(getPbxProjFile(), completeKey, value) } else { + plistHelperProperty.get() .setValueForPlist(getPbxProjFile(), completeKey, value) } From 8da79835596d710cd61e2005d231991969db6557 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Jul 2018 15:35:16 +0100 Subject: [PATCH 33/36] Add task dependency --- .../org/openbakery/PrepareXcodeArchivingTask.groovy | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index e6a2e6be..3d0c791b 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -10,6 +10,7 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.extension.TargetConfiguration +import org.openbakery.signing.KeychainCreateTask import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper import org.openbakery.util.SignatureUtil @@ -56,6 +57,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { PrepareXcodeArchivingTask() { super() + this.dependsOn(KeychainCreateTask.TASK_NAME) this.description = DESCRIPTION this.entitlementsFilePath.set(entitlementsFile.map(new Transformer() { @@ -86,6 +88,16 @@ class PrepareXcodeArchivingTask extends DefaultTask { this.outputFile.set(project.layout .buildDirectory .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) + + this.onlyIf { +// println "configurationBundleIdentifier :>> " + configurationBundleIdentifier +// println "provisioningForConfiguration : " + provisioningForConfiguration +// println "certificateFriendlyName : " + certificateFriendlyName + return certificateFriendlyName.present +// && +// configurationBundleIdentifier.present && +// provisioningForConfiguration.present + } } private File getPbxProjFile() { From e809070dbfb3a4fa198d0113821f8c748f5e5acf Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 20 Jul 2018 15:14:50 +0100 Subject: [PATCH 34/36] Allow to customise the version and shortversion for all the build configurationi It avoid AppStore rejection due to the extension has not the same version number and short version than the main proejct Fixes: #DRTV-554 --- .../PrepareXcodeArchivingTask.groovy | 30 +++++++++++++++++++ .../extension/TargetConfiguration.groovy | 2 ++ 2 files changed, 32 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 3d0c791b..e2e29baa 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -166,6 +166,8 @@ class PrepareXcodeArchivingTask extends DefaultTask { getValueFromPbxProjFile("rootObject") as String, tc.name)) + configurePlist(buildConfigurationId, tc) + map.each { k, v -> setBuildConfigurationBuildSetting(buildConfigurationId, k, v) } @@ -223,4 +225,32 @@ class PrepareXcodeArchivingTask extends DefaultTask { return file } + + private void configurePlist(String buildConfigurationId, + TargetConfiguration tc) { + String plistPath = getValueFromPbxProjFile( + ":objects:${buildConfigurationId}:buildSettings:INFOPLIST_FILE") + + File file = project.rootProject.file(plistPath) + assert file.exists() + + setValueOrCreate(file, "CFBundleVersion", tc.version) + setValueOrCreate(file, "CFBundleShortVersionString", tc.shortVersion) + } + + private void setValueOrCreate(File file, + String key, + String value) { + + String currentValue = plistHelperProperty.get() + .getValueFromPlist(file, key) + + if (currentValue == null) { + plistHelperProperty.get() + .addValueForPlist(file, key, value) + } else { + plistHelperProperty.get() + .setValueForPlist(file, key, value) + } + } } diff --git a/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy b/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy index 058b1296..148366b5 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/TargetConfiguration.groovy @@ -10,6 +10,8 @@ class TargetConfiguration implements Serializable { public String certificatePassword public String bundleIdentifier public File entitlementsFile + public String version + public String shortVersion private final String name From 60e735e10ab9bc936dfe943e27e4a63ba3c5c22c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 19 Feb 2019 16:01:31 +0000 Subject: [PATCH 35/36] Do not set a null value into the plist file It seems that in some cases the value could be null, and it was overriding the versioning with null as version. To avoid that issue, add a checker to ensure that when the build configuration does not has it's own versioning, it does not cancel the main project versioning. Resolves: #BTVAXIS-1511 --- .../src/main/groovy/org/openbakery/util/PlistHelper.groovy | 4 ++-- plugin/build.gradle | 2 +- .../groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy index 256e23d1..cec046c9 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy @@ -98,10 +98,10 @@ class PlistHelper { void setValueForPlist(File plist, String key, String value) { - commandForPlist(plist, "Set :" + key + " " + value) + if (value != null) + commandForPlist(plist, "Set :" + key + " " + value) } - void commandForPlist(File plist, String command) { if (!plist.exists()) { throw new IllegalStateException("Info Plist does not exist: " + plist.absolutePath); diff --git a/plugin/build.gradle b/plugin/build.gradle index 83cac330..32b9c6d1 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -98,7 +98,7 @@ uploadArchives { mavenDeployer { configuration = configurations.deployerJars - repository(url: publishURL) { + repository(url: mavenLocal().url) { authentication(userName: publishUser, password: publishPassword) } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index e2e29baa..27da3182 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -234,8 +234,11 @@ class PrepareXcodeArchivingTask extends DefaultTask { File file = project.rootProject.file(plistPath) assert file.exists() - setValueOrCreate(file, "CFBundleVersion", tc.version) - setValueOrCreate(file, "CFBundleShortVersionString", tc.shortVersion) + if (tc.version != null) + setValueOrCreate(file, "CFBundleVersion", tc.version) + + if (tc.shortVersion != null) + setValueOrCreate(file, "CFBundleShortVersionString", tc.shortVersion) } private void setValueOrCreate(File file, From c25cc83da895aebf4fa9fc1e5c7271ec1d0124e3 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 16 Jan 2020 16:09:01 +0000 Subject: [PATCH 36/36] feature : Add workspace support Add the support of workspace compilation for Cocoapods --- .../org/openbakery/xcode/Xcodebuild.groovy | 1 + .../XcodeBuildPluginExtension.groovy | 2 +- .../groovy/org/openbakery/XcodePlugin.groovy | 1 + .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 28 +++++++++++++++---- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index d25532a7..0989e05c 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -20,6 +20,7 @@ class Xcodebuild { public static final String ACTION_ARCHIVE = "archive" public static final String ACTION_EXPORT_ARCHIVE = "-exportArchive" public static final String ARGUMENT_CONFIGURATION = "-configuration" + public static final String ARGUMENT_WORKSPACE = "-workspace" public static final String ARGUMENT_SCHEME = "-scheme" public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" public static final String ARGUMENT_EXPORT_PATH = "-exportPath" diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index a20f8997..a8887183 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -149,7 +149,7 @@ class XcodeBuildPluginExtension { if (workspace != null) { return workspace } - String[] fileList = project.projectDir.list(new SuffixFileFilter(".xcworkspace")) + String[] fileList = project.rootProject.projectDir.list(new SuffixFileFilter(".xcworkspace")) if (fileList != null && fileList.length) { return fileList[0] } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index c7409edd..453262ee 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -512,6 +512,7 @@ class XcodePlugin implements Plugin { it.scheme.set(xcodeBuildPluginExtension.scheme) it.xcode.set(xcode) it.xcodeVersion.set(xcodeBuildPluginExtension.version) + it.workspace.set(xcodeBuildPluginExtension.workspace) it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 0bbc08e5..fd98b3dc 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -28,6 +28,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { @Input final Provider scheme = project.objects.property(String) + final Provider workspace = project.objects.property(String) + @Input final Provider buildType = project.objects.property(Type) @@ -60,7 +62,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { @TaskAction void archive() { - logger.info("Archive project with configuration: " + + println("Archive project with configuration: " + "\n\tScheme : ${scheme.getOrNull()} " + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}" + "\n\tBuild configuration : ${buildConfiguration.getOrNull()}") @@ -78,11 +80,25 @@ class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { assert buildConfiguration.present: "No build configuration configured" assert outputArchiveFile.present: "No output file folder configured" - ProcessBuilder builder = new ProcessBuilder("xcodebuild", - Xcodebuild.ACTION_ARCHIVE, - Xcodebuild.ARGUMENT_SCHEME, scheme.get(), - Xcodebuild.ARGUMENT_CONFIGURATION, buildConfiguration.get(), - Xcodebuild.ARGUMENT_ARCHIVE_PATH, outputArchiveFile.get().asFile.absolutePath) + + ProcessBuilder builder + + ArrayList args = new ArrayList([ + "xcodebuild", + Xcodebuild.ACTION_ARCHIVE, + Xcodebuild.ARGUMENT_SCHEME, scheme.get(), + Xcodebuild.ARGUMENT_CONFIGURATION, buildConfiguration.get(), + Xcodebuild.ARGUMENT_ARCHIVE_PATH, outputArchiveFile.get().asFile.absolutePath + ]) + + if (workspace.isPresent()) { + args.add(Xcodebuild.ARGUMENT_WORKSPACE) + args.add(workspace.get()) + } + + logger.debug("Running : ", args.join(" ")) + + builder = new ProcessBuilder(args) builder.directory(project.rootProject.rootDir)