From 33fd954c6f362f37abce68dbd5f2b1a528f26380 Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Mon, 9 Apr 2018 18:26:57 +0100 Subject: [PATCH 001/121] Archive tvOS --- .../groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 4810d071..61b94526 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -112,7 +112,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") List icons - if (parameters.type == Type.iOS) { + if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { icons = getiOSIcons() } else { icons = getMacOSXIcons() @@ -258,8 +258,8 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { def createEntitlements(File bundle) { - if (parameters.type != Type.iOS) { - logger.warn("Entitlements handling is only implemented for iOS!") + if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { + logger.warn("Entitlements handling is only implemented for iOS and tvOS!") return } @@ -337,7 +337,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { @TaskAction def archive() { parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) - if (parameters.isSimulatorBuildOf(Type.iOS)) { + if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { logger.debug("Create zip archive") // create zip archive @@ -398,7 +398,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { deleteFrameworksInExtension(applicationsDirectory) copyBCSymbolMaps(archiveDirectory) - if (project.xcodebuild.type == Type.iOS) { + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) convertInfoPlistToBinary(applicationFolder) } From 3e63fdd73a25f2f432b7ea249c62f1304fa15568 Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Mon, 9 Apr 2018 18:32:26 +0100 Subject: [PATCH 002/121] tvOS package --- .../org/openbakery/packaging/PackageTask.groovy | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index 0e83d88f..287f6f0c 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -46,7 +46,7 @@ class PackageTask extends AbstractDistributeTask { @TaskAction void packageApplication() throws IOException { - if (project.xcodebuild.isSimulatorBuildOf(Type.iOS)) { + if (project.xcodebuild.isSimulatorBuildOf(Type.iOS) || project.xcodebuild.isSimulatorBuildOf(Type.tvOS)) { logger.lifecycle("not a device build, so no codesign and packaging needed") return } @@ -107,9 +107,11 @@ class PackageTask extends AbstractDistributeTask { codesignParameters.keychain = project.xcodebuild.signing.keychainPathInternal Codesign codesign = new Codesign(xcode, codesignParameters, commandRunner, plistHelper) + def isDeviceBuild = project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS) + for (File bundle : appBundles) { - if (project.xcodebuild.isDeviceBuildOf(Type.iOS)) { + if (isDeviceBuild) { removeFrameworkFromExtensions(bundle) removeUnneededDylibsFromBundle(bundle) embedProvisioningProfileToBundle(bundle) @@ -125,7 +127,7 @@ class PackageTask extends AbstractDistributeTask { } File appBundle = appBundles.last() - if (project.xcodebuild.isDeviceBuildOf(Type.iOS)) { + if (isDeviceBuild) { boolean isAdHoc = isAdHoc(appBundle) createIpa(applicationFolder, !isAdHoc) @@ -240,7 +242,7 @@ class PackageTask extends AbstractDistributeTask { private String getIdentifierForBundle(File bundle) { File infoPlist - if (project.xcodebuild.isDeviceBuildOf(Type.iOS)) { + if (project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS)) { infoPlist = new File(bundle, "Info.plist"); } else { infoPlist = new File(bundle, "Contents/Info.plist") @@ -276,7 +278,7 @@ class PackageTask extends AbstractDistributeTask { private File createApplicationFolder() throws IOException { - if (project.xcodebuild.isDeviceBuildOf(Type.iOS)) { + if (project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS)) { return createSigningDestination("Payload") } else { // same folder as signing @@ -297,7 +299,7 @@ class PackageTask extends AbstractDistributeTask { } private String getAppContentPath(File bundle) { - if (project.xcodebuild.type == Type.iOS) { + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { return bundle.absolutePath + "/" } return bundle.absolutePath + "/Contents/" From 2f1f848a565416dc9a2c8dc4b2817c266783f0ac Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Mon, 9 Apr 2018 20:07:50 +0100 Subject: [PATCH 003/121] tvOS simulator --- .../org/openbakery/simulators/SimulatorControl.groovy | 9 +++++---- .../org/openbakery/XcodeBuildPluginExtension.groovy | 6 ++++++ .../org/openbakery/simulators/SimulatorRunAppTask.groovy | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index eb8bd698..a9867174 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -219,16 +219,17 @@ class SimulatorControl { SimulatorRuntime getRuntime(Destination destination) { + def targetType = destination.platform == 'tvOS Simulator' ? Type.tvOS : Type.iOS for (SimulatorRuntime runtime in getRuntimes()) { - if (runtime.type == Type.iOS && runtime.version.equals(new Version(destination.os))) { - return runtime; + if (runtime.type == targetType && runtime.version.equals(new Version(destination.os))) { + return runtime } } - return null; + return null } SimulatorDevice getDevice(Destination destination) { - SimulatorRuntime runtime = getRuntime(destination); + SimulatorRuntime runtime = getRuntime(destination) if (runtime != null) { for (SimulatorDevice device in getDevices(runtime)) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 921e333e..4f2592bc 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -337,6 +337,12 @@ class XcodeBuildPluginExtension { } else { path += "-iphoneos" } + } else if (type == Type.tvOS) { + if (simulator) { + path += "-appletvsimulator" + } else { + path += "-appletv" + } } return new File(getSymRoot(), path) } diff --git a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorRunAppTask.groovy b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorRunAppTask.groovy index b9ed6105..56e3ae45 100644 --- a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorRunAppTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorRunAppTask.groovy @@ -22,7 +22,7 @@ class SimulatorRunAppTask extends AbstractSimulatorTask { @TaskAction void run() { - if (!project.xcodebuild.isSimulatorBuildOf(Type.iOS)) { + if (!project.xcodebuild.isSimulatorBuildOf(Type.iOS) && !project.xcodebuild.isSimulatorBuildOf(Type.tvOS)) { throw new IllegalArgumentException("Build is not a simulator build for iOS: Is " + project.xcodebuild.type + " and simulator flag is " + project.xcodebuild.simulator ) } From 7d51dab5e6d3cf349cd5e2a01b8f4a4e0dfb595b Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Mon, 9 Apr 2018 22:50:19 +0100 Subject: [PATCH 004/121] Tidy PackageTask --- .../openbakery/packaging/PackageTask.groovy | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index 287f6f0c..fc0eee3b 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -29,8 +29,8 @@ class PackageTask extends AbstractDistributeTask { CodesignParameters codesignParameters = new CodesignParameters() PackageTask() { - super(); - setDescription("Signs the app bundle that was created by the build and creates the ipa"); + super() + setDescription("Signs the app bundle that was created by the build and creates the ipa") dependsOn( XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, @@ -107,11 +107,9 @@ class PackageTask extends AbstractDistributeTask { codesignParameters.keychain = project.xcodebuild.signing.keychainPathInternal Codesign codesign = new Codesign(xcode, codesignParameters, commandRunner, plistHelper) - def isDeviceBuild = project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS) - for (File bundle : appBundles) { - if (isDeviceBuild) { + if (isDeviceBuildiOStvOS()) { removeFrameworkFromExtensions(bundle) removeUnneededDylibsFromBundle(bundle) embedProvisioningProfileToBundle(bundle) @@ -127,7 +125,7 @@ class PackageTask extends AbstractDistributeTask { } File appBundle = appBundles.last() - if (isDeviceBuild) { + if (isDeviceBuildiOStvOS()) { boolean isAdHoc = isAdHoc(appBundle) createIpa(applicationFolder, !isAdHoc) @@ -137,8 +135,9 @@ class PackageTask extends AbstractDistributeTask { } - - + boolean isDeviceBuildiOStvOS() { + return project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS) + } boolean isAdHoc(File appBundle) { File provisionFile = getProvisionFileForBundle(appBundle) @@ -238,11 +237,10 @@ class PackageTask extends AbstractDistributeTask { } - private String getIdentifierForBundle(File bundle) { File infoPlist - if (project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS)) { + if (isDeviceBuildiOStvOS()) { infoPlist = new File(bundle, "Info.plist"); } else { infoPlist = new File(bundle, "Contents/Info.plist") @@ -268,9 +266,9 @@ class PackageTask extends AbstractDistributeTask { } private File createSigningDestination(String name) throws IOException { - File destination = new File(outputPath, name); + File destination = new File(outputPath, name) if (destination.exists()) { - FileUtils.deleteDirectory(destination); + FileUtils.deleteDirectory(destination) } destination.mkdirs(); return destination; @@ -278,7 +276,7 @@ class PackageTask extends AbstractDistributeTask { private File createApplicationFolder() throws IOException { - if (project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS)) { + if (isDeviceBuildiOStvOS()) { return createSigningDestination("Payload") } else { // same folder as signing From c38c494a2fd97593220f215dcf47b58368ddae8b Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Tue, 10 Apr 2018 13:13:18 +0100 Subject: [PATCH 005/121] Fixed target name --- .../main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 4f2592bc..6e83294a 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -341,7 +341,7 @@ class XcodeBuildPluginExtension { if (simulator) { path += "-appletvsimulator" } else { - path += "-appletv" + path += "-appletvos" } } return new File(getSymRoot(), path) From 3bd7c52a26c878171e88e8e7705d4c9f70a61668 Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Tue, 10 Apr 2018 13:59:53 +0100 Subject: [PATCH 006/121] Missing tvOS output path --- .../groovy/org/openbakery/xcode/XcodebuildParameters.groovy | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy index 2352a55c..115b7510 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy @@ -147,6 +147,12 @@ class XcodebuildParameters { } else { return new File(getSymRoot(), "${configuration}-iphoneos") } + } else if (type == Type.tvOS) { + if (simulator) { + return new File(getSymRoot(), "${configuration}-appletvsimulator") + } else { + return new File(getSymRoot(), "${configuration}-appletvos") + } } return new File(getSymRoot(), configuration) } From 1ab48836596b973566fa071b64b019be6d48c348 Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Tue, 10 Apr 2018 14:22:23 +0100 Subject: [PATCH 007/121] Test tvOS output --- ...deBuildPluginExtensionSpecification.groovy | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy index a7478786..ae36f058 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy @@ -194,6 +194,28 @@ class XcodeBuildPluginExtensionSpecification extends Specification { } + def "application bundle for tvOS"() { + when: + File projectDir = new File("../example/tvOS/Example_tvOS_Swift") + project = ProjectBuilder.builder().withProjectDir(projectDir).build() + extension = new XcodeBuildPluginExtension(project) + extension.commandRunner = new CommandRunner() + XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example_tvOS_Swift.xcodeproj/project.pbxproj")) + extension.projectSettings = xcodeProjectFile.getProjectSettings() + + extension.type = Type.tvOS + extension.simulator = false + extension.target = "Example_tvOS_Swift" + extension.productName = "Example_tvOS_Swift" + extension.infoPlist = "../../example/tvOS/Example_tvOS_Swift/Example_tvOS_Swift/Info.plist" + + String applicationBundle = extension.getApplicationBundle().absolutePath; + + then: + applicationBundle.endsWith("build/sym/Debug-appletvos/Example_tvOS_Swift.app") + + } + def "application bundle for watchos"() { when: @@ -410,6 +432,24 @@ class XcodeBuildPluginExtensionSpecification extends Specification { } + def "get binary tvOS"() { + when: + File projectDir = new File("../example/tvOS/Example_tvOS_Swift") + project = ProjectBuilder.builder().withProjectDir(projectDir).build() + extension = new XcodeBuildPluginExtension(project) + XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example_tvOS_Swift.xcodeproj/project.pbxproj")) + extension.projectSettings = xcodeProjectFile.getProjectSettings() + extension.type = Type.tvOS + extension.simulator = false + extension.target = "Example_tvOS_Swift" + extension.productType = "appex" + extension.infoPlist = "../../example/tvOS/Example_tvOS_Swift/Example_tvOS_Swift/Info.plist" + + then: + extension.getBinary().toString().endsWith("Debug-appletvos/Example_tvOS_Swift.app/Example_tvOS_Swift") + } + + def "get binary OS X"() { when: File projectDir = new File("../example/OSX/ExampleOSX") From a6cade13be408d3783ef01c3188600a651f0e126 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 11:51:29 +0100 Subject: [PATCH 008/121] Refactor the type resolution --- .gitignore | 2 + .../org/openbakery/xcode/Destination.groovy | 4 +- .../groovy/org/openbakery/xcode/Type.groovy | 44 +++++++++---------- .../xcode/DestinationSpecification.groovy | 20 +++++++++ 4 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy diff --git a/.gitignore b/.gitignore index 2a370490..6fd45edc 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ xcuserdata .idea/ *.iml local.properties + +out/ diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy index 587ef405..63b0d78e 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy @@ -27,7 +27,7 @@ class Destination { } @Override - public java.lang.String toString() { + public String toString() { return "Destination{" + "platform='" + platform + '\'' + ", name='" + name + '\'' + @@ -67,7 +67,7 @@ class Destination { } - public java.lang.String toPrettyString() { + public String toPrettyString() { StringBuilder builder = new StringBuilder() builder.append(name) if (!StringUtils.isEmpty(platform)) { diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy index ee474a1f..c29485a1 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy @@ -1,31 +1,29 @@ package org.openbakery.xcode enum Type { - iOS("iOS"), - macOS("macOS"), - tvOS("tvOS"), - watchOS("watchOS") + iOS("iOS"), + macOS("macOS"), + tvOS("tvOS"), + watchOS("watchOS") + private final String value - String value; + Type(String value) { + this.value = value + } - Type(String value) { - this.value = value - } + String getValue() { + return value + } - static Type typeFromString(String string) { - if (string == null) { - return iOS - } - for (Type type in Type.values()) { - // for backward compatibility - if (string.toLowerCase().equalsIgnoreCase("osx")) { - return Type.macOS - } - if (string.toLowerCase().startsWith(type.value.toLowerCase())) { - return type - } - } - return iOS - } + static Type typeFromString(final String string) { + Type result = values() + .findAll { string?.toLowerCase()?.startsWith(it.value.toLowerCase()) } + .find() + + result = result ?: + (string?.toLowerCase()?.startsWith("osx") ? macOS : null) + + return result + } } diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy new file mode 100644 index 00000000..c19a621f --- /dev/null +++ b/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy @@ -0,0 +1,20 @@ +package org.openbakery.xcode + +import spock.lang.Specification + +class DestinationSpecification extends Specification { + + def "A destination target type should be resolved successfully from it's platform"() { + expect: + Type.typeFromString(platform) == target + + where: + platform | target + "iOS Simulator" | Type.iOS + "tvOS Simulator" | Type.tvOS + "watchOS Simulator" | Type.watchOS + "invalid" | null + "" | null + null | null + } +} From b9d0ab47c136e56d19121f0e88473b2550d9c0f9 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 11:56:46 +0100 Subject: [PATCH 009/121] Refactor the type resolution --- .../src/main/groovy/org/openbakery/xcode/Type.groovy | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy index c29485a1..c9ccd94c 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Type.groovy @@ -8,6 +8,8 @@ enum Type { private final String value + private static final String BACKWARD_COMPATIBILITY_MAC_OS = "osx" + Type(String value) { this.value = value } @@ -17,13 +19,8 @@ enum Type { } static Type typeFromString(final String string) { - Type result = values() + return values() .findAll { string?.toLowerCase()?.startsWith(it.value.toLowerCase()) } - .find() - - result = result ?: - (string?.toLowerCase()?.startsWith("osx") ? macOS : null) - - return result + .find() ?: (string?.toLowerCase()?.startsWith(BACKWARD_COMPATIBILITY_MAC_OS) ? macOS : null) } } From 5ea2a28ed46559ad9e7a7b317835f960b25ae9a9 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 13:06:40 +0100 Subject: [PATCH 010/121] Simplify and add unit tests --- .../simulators/SimulatorControl.groovy | 32 +++---- .../simulators/SimulatorRuntime.groovy | 6 +- .../org/openbakery/xcode/Destination.groovy | 4 + .../SimulatorControlSpecification.groovy | 94 ++++++++++--------- .../xcode/DestinationSpecification.groovy | 2 +- .../openbakery/xcode/TypeSpecification.groovy | 28 +++--- 6 files changed, 90 insertions(+), 76 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index a9867174..8a569f4c 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -1,6 +1,7 @@ package org.openbakery.simulators -import org.openbakery.* +import org.openbakery.CommandRunner +import org.openbakery.CommandRunnerException import org.openbakery.xcode.Destination import org.openbakery.xcode.Type import org.openbakery.xcode.Version @@ -11,7 +12,6 @@ import org.slf4j.LoggerFactory class SimulatorControl { - enum Section { DEVICE_TYPE("== Device Types =="), RUNTIMES("== Runtimes =="), @@ -19,6 +19,7 @@ class SimulatorControl { DEVICE_PAIRS("== Device Pairs ==") private final String identifier + Section(String identifier) { this.identifier = identifier } @@ -48,9 +49,6 @@ class SimulatorControl { ArrayList devicePairs - - - public SimulatorControl(CommandRunner commandRunner, Xcode xcode) { this.commandRunner = commandRunner this.xcode = xcode @@ -60,7 +58,7 @@ class SimulatorControl { runtimes = new ArrayList<>() devices = new HashMap<>() deviceTypes = new ArrayList<>() - identifierToDevice = new HashMap<>() + identifierToDevice = new HashMap<>() devicePairs = new ArrayList<>() @@ -103,7 +101,7 @@ class SimulatorControl { if (simulatorDevices != null) { SimulatorDevice device = new SimulatorDevice(line) simulatorDevices.add(device) - identifierToDevice[device.identifier]=device + identifierToDevice[device.identifier] = device } break @@ -136,7 +134,7 @@ class SimulatorControl { tokenizer.nextToken() } if (tokenizer.hasMoreTokens()) { - def identifier = tokenizer.nextToken().trim() + def identifier = tokenizer.nextToken().trim() return getDeviceWithIdentifier(identifier) } return null @@ -207,7 +205,6 @@ class SimulatorControl { } - SimulatorDevice getDevice(SimulatorRuntime simulatorRuntime, String name) { for (SimulatorDevice device in getDevices(simulatorRuntime)) { if (device.name.equalsIgnoreCase(name)) { @@ -219,13 +216,10 @@ class SimulatorControl { SimulatorRuntime getRuntime(Destination destination) { - def targetType = destination.platform == 'tvOS Simulator' ? Type.tvOS : Type.iOS - for (SimulatorRuntime runtime in getRuntimes()) { - if (runtime.type == targetType && runtime.version.equals(new Version(destination.os))) { - return runtime - } - } - return null + return getRuntimes() + .findAll { it.type == destination.targetType } + .findAll { it.version?.equals(new Version(destination.os)) } + .find() } SimulatorDevice getDevice(Destination destination) { @@ -252,7 +246,7 @@ class SimulatorControl { return null } - List getDevices(SimulatorRuntime runtime) { + List getDevices(SimulatorRuntime runtime) { return getDevices().get(runtime) } @@ -281,15 +275,13 @@ class SimulatorControl { String simctl(String... commands) { - ArrayListparameters = new ArrayList<>() + ArrayList parameters = new ArrayList<>() parameters.add(xcode.getSimctl()) parameters.addAll(commands) return commandRunner.runWithResult(parameters) } - - void deleteAll() { for (Map.Entry> entry : getDevices().entrySet()) { diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorRuntime.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorRuntime.groovy index a2cf1636..19b82116 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorRuntime.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorRuntime.groovy @@ -57,7 +57,11 @@ class SimulatorRuntime { } - @Override + Type getType() { + return type + } + + @Override public String toString() { return "SimulatorRuntime{" + "name='" + name + '\'' + diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy index 63b0d78e..c049555f 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy @@ -26,6 +26,10 @@ class Destination { this.os = os } + public Type getTargetType() { + return Type.typeFromString(platform) + } + @Override public String toString() { return "Destination{" + diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 8f94d4aa..1cc1c06f 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -12,10 +12,18 @@ class SimulatorControlSpecification extends Specification { File projectDir SimulatorControl simulatorControl - CommandRunner commandRunner = Mock(CommandRunner); - Xcode xcode = Mock(Xcode); + CommandRunner commandRunner = Mock(CommandRunner) + Xcode xcode = Mock(Xcode) - def SIMCTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" + private static + final String SIM_CTL_LIST_UNAVAILABLE = "src/test/Resource/simctl-list-unavailable.txt" + + private static final String RES_PATH = "src/test/Resource" + private static final String SIMCTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" + private static final String SIM_CTL_LIST_XCODE7 = "${RES_PATH}/simctl-list-xcode7.txt" + private static final String SIM_CTL_LIST_XCODE8 = "${RES_PATH}/simctl-list-xcode8.txt" + private static final String SIM_CTL_LIST_XCODE9 = "${RES_PATH}/simctl-list-xcode9.txt" + private static final String SIM_CTL_LIST_XCODE9_1 = "${RES_PATH}/simctl-list-xcode9_1.txt" def setup() { xcode.getSimctl() >> SIMCTL @@ -28,23 +36,27 @@ class SimulatorControlSpecification extends Specification { void mockXcode6() { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-unavailable.txt")) + mockWithFile(SIM_CTL_LIST_UNAVAILABLE) } void mockXcode7() { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7.txt")) + mockWithFile(SIM_CTL_LIST_XCODE7) } void mockXcode8() { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode8.txt")) + mockWithFile(SIM_CTL_LIST_XCODE8) } void mockXcode9() { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode9.txt")) + mockWithFile(SIM_CTL_LIST_XCODE9) } void mockXcode9_1() { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode9_1.txt")) + mockWithFile(SIM_CTL_LIST_XCODE9_1) + } + + void mockWithFile(String uri) { + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File(uri)) } @@ -52,7 +64,6 @@ class SimulatorControlSpecification extends Specification { given: mockXcode6() - expect: List runtimes = simulatorControl.getRuntimes() @@ -73,7 +84,6 @@ class SimulatorControlSpecification extends Specification { runtime1.identifier.equals("com.apple.CoreSimulator.SimRuntime.iOS-7-1") } - def "get most recent iOS runtime"() { given: @@ -145,7 +155,6 @@ class SimulatorControlSpecification extends Specification { } - def "devices iOS7"() { given: mockXcode6() @@ -163,7 +172,6 @@ class SimulatorControlSpecification extends Specification { } - def "devices iOS8"() { given: mockXcode6() @@ -181,8 +189,6 @@ class SimulatorControlSpecification extends Specification { } - - def "delete All"() { given: mockXcode6() @@ -191,22 +197,22 @@ class SimulatorControlSpecification extends Specification { simulatorControl.deleteAll() then: - 1* commandRunner.runWithResult([SIMCTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) - 1* commandRunner.runWithResult([SIMCTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) } @@ -526,7 +532,6 @@ class SimulatorControlSpecification extends Specification { } - def "xcode 8 has Apple TV device type "() { given: mockXcode8() @@ -642,7 +647,7 @@ class SimulatorControlSpecification extends Specification { } - def "devices iOS11.1 runtimes" () { + def "devices iOS11.1 runtimes"() { given: mockXcode9_1() @@ -655,21 +660,26 @@ class SimulatorControlSpecification extends Specification { runtimes.get(0).name == "iOS 11.1" } - def "devices iOS11.1"() { + def "test the different runtime and device of XCode 9.1"() { given: mockXcode9_1() - when: + expect: List runtimes = simulatorControl.getRuntimes() - SimulatorRuntime runtime = runtimes.get(0) - List devices = simulatorControl.getDevices(runtimes.get(0)) + SimulatorRuntime runtime = runtimes.find { it.type == runtimeType } - then: - devices != null - devices.size() == 18 - runtime.name == "iOS 11.1" - } + runtime != null + runtime.name == runtimeName + runtime.type == runtimeType -} + simulatorControl.getDevices(runtime) + .size() == deviceCount + where: + runtimeType | runtimeName | deviceCount + Type.tvOS | "tvOS 11.1" | 3 + Type.iOS | "iOS 11.1" | 18 + Type.watchOS | "watchOS 4.1" | 6 + } +} diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy index c19a621f..1d51bd3f 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/DestinationSpecification.groovy @@ -6,7 +6,7 @@ class DestinationSpecification extends Specification { def "A destination target type should be resolved successfully from it's platform"() { expect: - Type.typeFromString(platform) == target + new Destination(platform, null, null).targetType == target where: platform | target diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/TypeSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/TypeSpecification.groovy index 7a091137..d8f60952 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/TypeSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/TypeSpecification.groovy @@ -4,19 +4,23 @@ import spock.lang.Specification class TypeSpecification extends Specification { - def "typeFromString give proper type"() { expect: - Type.typeFromString("macOS") == Type.macOS - Type.typeFromString("MacOS") == Type.macOS - Type.typeFromString("macos") == Type.macOS - Type.typeFromString("OSX") == Type.macOS - Type.typeFromString("osx") == Type.macOS - Type.typeFromString("Osx") == Type.macOS - Type.typeFromString("ios") == Type.iOS - Type.typeFromString("IOS") == Type.iOS - Type.typeFromString("iOS") == Type.iOS - Type.typeFromString("tvOS") == Type.tvOS - Type.typeFromString("tvos") == Type.tvOS + Type.typeFromString(value) == type + + where: + value | type + "macOS" | Type.macOS + "MacOS" | Type.macOS + "macos" | Type.macOS + "OSX" | Type.macOS + "osx" | Type.macOS + "Osx" | Type.macOS + "ios" | Type.iOS + "IOS" | Type.iOS + "iOS" | Type.iOS + "iOS 7.1 (7.1 - 11D167) (com.apple.CoreSimulator.SimRuntime.iOS-7-1)" | Type.iOS + "tvOS" | Type.tvOS + "tvos" | Type.tvOS } } From 470dd7377711b39946eadda34449c8c6f1f22e30 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 14:00:11 +0100 Subject: [PATCH 011/121] Simplify unit tests --- .../SimulatorControlSpecification.groovy | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 1cc1c06f..4b34a427 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -7,6 +7,7 @@ import org.openbakery.xcode.Type import org.openbakery.xcode.Version import org.openbakery.xcode.Xcode import spock.lang.Specification +import spock.lang.Unroll class SimulatorControlSpecification extends Specification { @@ -646,27 +647,14 @@ class SimulatorControlSpecification extends Specification { devices.size() == 15 } - - def "devices iOS11.1 runtimes"() { - given: - mockXcode9_1() - - when: - List runtimes = simulatorControl.getRuntimes() - - then: - runtimes != null - runtimes.size() == 3 - runtimes.get(0).name == "iOS 11.1" - } - - def "test the different runtime and device of XCode 9.1"() { - given: - mockXcode9_1() - + @Unroll + def "test the runTime with value #runtimeType with name : #runtimeName and #deviceCount devices"() { expect: - List runtimes = simulatorControl.getRuntimes() - SimulatorRuntime runtime = runtimes.find { it.type == runtimeType } + mockWithFile(ctlFile) + + SimulatorRuntime runtime = simulatorControl + .getRuntimes() + .find { it.type == runtimeType } runtime != null runtime.name == runtimeName @@ -676,10 +664,11 @@ class SimulatorControlSpecification extends Specification { .size() == deviceCount where: - runtimeType | runtimeName | deviceCount - Type.tvOS | "tvOS 11.1" | 3 - Type.iOS | "iOS 11.1" | 18 - Type.watchOS | "watchOS 4.1" | 6 + ctlFile | runtimeType | runtimeName | deviceCount + SIM_CTL_LIST_XCODE9_1 | Type.tvOS | "tvOS 11.1" | 3 + SIM_CTL_LIST_XCODE9_1 | Type.iOS | "iOS 11.1" | 18 + SIM_CTL_LIST_XCODE9_1 | Type.watchOS | "watchOS 4.1" | 6 + SIM_CTL_LIST_XCODE9 | Type.iOS | "iOS 11.0" | 15 } } From 39cf7ab6e5aa72fc9d1cfe840625597627b6dafd Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 14:08:12 +0100 Subject: [PATCH 012/121] Adjustements --- .../SimulatorControlSpecification.groovy | 197 +++++++++--------- 1 file changed, 98 insertions(+), 99 deletions(-) diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 4b34a427..7cbeff76 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -20,14 +20,14 @@ class SimulatorControlSpecification extends Specification { final String SIM_CTL_LIST_UNAVAILABLE = "src/test/Resource/simctl-list-unavailable.txt" private static final String RES_PATH = "src/test/Resource" - private static final String SIMCTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" + private static final String SIM_CTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" private static final String SIM_CTL_LIST_XCODE7 = "${RES_PATH}/simctl-list-xcode7.txt" private static final String SIM_CTL_LIST_XCODE8 = "${RES_PATH}/simctl-list-xcode8.txt" private static final String SIM_CTL_LIST_XCODE9 = "${RES_PATH}/simctl-list-xcode9.txt" private static final String SIM_CTL_LIST_XCODE9_1 = "${RES_PATH}/simctl-list-xcode9_1.txt" def setup() { - xcode.getSimctl() >> SIMCTL + xcode.getSimctl() >> SIM_CTL xcode.getPath() >> "/Applications/Xcode.app" simulatorControl = new SimulatorControl(commandRunner, xcode) } @@ -57,7 +57,7 @@ class SimulatorControlSpecification extends Specification { } void mockWithFile(String uri) { - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File(uri)) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File(uri)) } @@ -102,7 +102,7 @@ class SimulatorControlSpecification extends Specification { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.iOS) @@ -116,7 +116,7 @@ class SimulatorControlSpecification extends Specification { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.tvOS) @@ -198,22 +198,22 @@ class SimulatorControlSpecification extends Specification { simulatorControl.deleteAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) - 1 * commandRunner.runWithResult([SIMCTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) + 1 * commandRunner.runWithResult([SIM_CTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) } @@ -225,26 +225,26 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) } @@ -257,22 +257,22 @@ class SimulatorControlSpecification extends Specification { simulatorControl.eraseAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "erase", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "15F68098-3B21-411D-B553-1C3161C100E7"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "454F3900-7B07-422E-A731-D46C821888B5"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "B8278DAC-97EE-4097-88CA-5650960882A5"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "0560469A-813F-4AF7-826C-4598802A7FFD"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "5C4434E1-81AC-4448-8237-26029A57E594"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "29C34492-7006-41D7-B634-8703972F725C"]) - 1 * commandRunner.runWithResult([SIMCTL, "erase", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "15F68098-3B21-411D-B553-1C3161C100E7"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "454F3900-7B07-422E-A731-D46C821888B5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "B8278DAC-97EE-4097-88CA-5650960882A5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "0560469A-813F-4AF7-826C-4598802A7FFD"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "5C4434E1-81AC-4448-8237-26029A57E594"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "29C34492-7006-41D7-B634-8703972F725C"]) + 1 * commandRunner.runWithResult([SIM_CTL, "erase", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) } @@ -315,7 +315,7 @@ class SimulatorControlSpecification extends Specification { def "devices iOS9.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List runtimes = simulatorControl.getRuntimes() @@ -342,20 +342,20 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) } @@ -367,8 +367,8 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "pair", "86895139-2FA4-4E97-A91A-C088A02F7BCD", "FE4BE76C-A3A1-4FB0-8BD4-7B87B4ACEDB2"]) - 1 * commandRunner.runWithResult([SIMCTL, "pair", "2A40D83C-EF8E-46AB-9C50-7DA01DA0B01F", "6F866EE0-55E8-439C-95F4-3FF19DAF553F"]) + 1 * commandRunner.runWithResult([SIM_CTL, "pair", "86895139-2FA4-4E97-A91A-C088A02F7BCD", "FE4BE76C-A3A1-4FB0-8BD4-7B87B4ACEDB2"]) + 1 * commandRunner.runWithResult([SIM_CTL, "pair", "2A40D83C-EF8E-46AB-9C50-7DA01DA0B01F", "6F866EE0-55E8-439C-95F4-3FF19DAF553F"]) } @@ -414,7 +414,7 @@ class SimulatorControlSpecification extends Specification { def "get 8.4 device for destination xcode 7.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) Destination destination = new Destination() destination.name = "iPad 2" destination.platform = 'iOS Simulator' @@ -431,7 +431,7 @@ class SimulatorControlSpecification extends Specification { def "get 9.1 device for destination xcode 7.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) Destination destination = new Destination() destination.name = "iPad 2" destination.platform = 'iOS Simulator' @@ -449,7 +449,7 @@ class SimulatorControlSpecification extends Specification { def "get all iOS simulator destinations"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List allDestinations = simulatorControl.getAllDestinations(Type.iOS) @@ -465,7 +465,7 @@ class SimulatorControlSpecification extends Specification { def "get all iOS simulator destinations of runtime"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.iOS) when: @@ -481,7 +481,7 @@ class SimulatorControlSpecification extends Specification { def "get all tvOS simulator destinations"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List allDestinations = simulatorControl.getAllDestinations(Type.tvOS) @@ -572,37 +572,36 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Pro (9.7-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Pro (12.9-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Pro (9.7-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Pro (12.9-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 7 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 7", "com.apple.CoreSimulator.SimDeviceType.iPhone-7", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 7 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 7", "com.apple.CoreSimulator.SimDeviceType.iPhone-7", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch Series 2 - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch Series 2 - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch Series 2 - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch Series 2 - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple TV 1080p", "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p", "com.apple.CoreSimulator.SimRuntime.tvOS-10-0"]) + 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple TV 1080p", "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p", "com.apple.CoreSimulator.SimRuntime.tvOS-10-0"]) } - def "devices iOS10"() { given: mockXcode8() @@ -648,7 +647,7 @@ class SimulatorControlSpecification extends Specification { } @Unroll - def "test the runTime with value #runtimeType with name : #runtimeName and #deviceCount devices"() { + def "Ensure than the compilation runtime: #runtimeType with name : #runtimeName and #deviceCount devices is properly defined"() { expect: mockWithFile(ctlFile) From 764f6b22a5a92eef7dcf9ed5935be999aeeda76a Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 16:43:24 +0100 Subject: [PATCH 013/121] Destination cleanup --- .../org/openbakery/xcode/Destination.groovy | 5 ++ .../xcode/XcodebuildParameters.groovy | 57 +++++++++---------- .../XcodebuildParametersSpecification.groovy | 28 +++++---- .../XcodeBuildPluginExtension.groovy | 23 +++----- 4 files changed, 59 insertions(+), 54 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy index c049555f..de42fafe 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy @@ -13,6 +13,11 @@ class Destination { String id = null String os = null + public static final String APPLE_TV_OS = "appletvos" + public static final String APPLE_TV_SIMULATOR = "appletvsimulator" + public static final String IPHONE_SIMULATOR = "iphonesimulator" + public static final String IPHONE_OS = "iphoneos" + Destination() { } diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy index 115b7510..c9116eeb 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy @@ -35,24 +35,24 @@ class XcodebuildParameters { @Override public String toString() { return "XcodebuildParameters {" + - ", scheme='" + scheme + '\'' + - ", target='" + target + '\'' + - ", simulator=" + simulator + - ", type=" + type + - ", workspace='" + workspace + '\'' + - ", configuration='" + configuration + '\'' + - ", bitcode=" + bitcode + - ", dstRoot=" + dstRoot + - ", objRoot=" + objRoot + - ", symRoot=" + symRoot + - ", sharedPrecompsDir=" + sharedPrecompsDir + - ", derivedDataPath=" + derivedDataPath + - ", arch=" + arch + - ", additionalParameters=" + additionalParameters + - ", configuredDestinations=" + configuredDestinations + - ", xctestrun=" + xctestrun + - ", applicationBundle=" + applicationBundle + - '}' + ", scheme='" + scheme + '\'' + + ", target='" + target + '\'' + + ", simulator=" + simulator + + ", type=" + type + + ", workspace='" + workspace + '\'' + + ", configuration='" + configuration + '\'' + + ", bitcode=" + bitcode + + ", dstRoot=" + dstRoot + + ", objRoot=" + objRoot + + ", symRoot=" + symRoot + + ", sharedPrecompsDir=" + sharedPrecompsDir + + ", derivedDataPath=" + derivedDataPath + + ", arch=" + arch + + ", additionalParameters=" + additionalParameters + + ", configuredDestinations=" + configuredDestinations + + ", xctestrun=" + xctestrun + + ", applicationBundle=" + applicationBundle + + '}' } @@ -98,7 +98,6 @@ class XcodebuildParameters { } - void setDestination(def destination) { if (destination instanceof List) { @@ -142,18 +141,18 @@ class XcodebuildParameters { File getOutputPath() { if (type == Type.iOS) { - if (simulator) { - return new File(getSymRoot(), "${configuration}-iphonesimulator") - } else { - return new File(getSymRoot(), "${configuration}-iphoneos") - } + return resolveSymRoot(simulator + ? Destination.IPHONE_SIMULATOR + : Destination.IPHONE_OS) } else if (type == Type.tvOS) { - if (simulator) { - return new File(getSymRoot(), "${configuration}-appletvsimulator") - } else { - return new File(getSymRoot(), "${configuration}-appletvos") - } + return resolveSymRoot(simulator + ? Destination.APPLE_TV_SIMULATOR + : Destination.APPLE_TV_OS) } return new File(getSymRoot(), configuration) } + + private File resolveSymRoot(String destination) { + return new File(getSymRoot(), "${configuration}-" + destination) + } } diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy index 4beb1d8a..04f1269d 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy @@ -1,11 +1,12 @@ package org.openbakery.xcode import spock.lang.Specification +import spock.lang.Unroll class XcodebuildParametersSpecification extends Specification { - XcodebuildParameters first = new XcodebuildParameters() + XcodebuildParameters first = new XcodebuildParameters() XcodebuildParameters second = new XcodebuildParameters() def setup() { @@ -16,7 +17,7 @@ class XcodebuildParametersSpecification extends Specification { first.workspace = "workspace" first.configuration = "configuration" first.additionalParameters = "additionalParameters" - first.devices = Devices.UNIVERSAL + first.devices = Devices.UNIVERSAL first.configuredDestinations = ["iPhone 4s"] } @@ -51,7 +52,6 @@ class XcodebuildParametersSpecification extends Specification { } - def "simulator is merged reverse"() { when: first.simulator = true @@ -174,7 +174,8 @@ class XcodebuildParametersSpecification extends Specification { first.outputPath == new File("sym/debug-iphonesimulator") } - def "outputPath with different configurations"(simulator, configuration, type, outputPath) { + @Unroll + def "path type: #type in config #type in #configuration mode and simulator:#simulator"() { when: first.configuration = configuration first.type = type @@ -182,15 +183,22 @@ class XcodebuildParametersSpecification extends Specification { first.symRoot = new File("sym") then: - first.outputPath == new File(outputPath) + File file = type == Type.macOS ? new File("sym/${outputPath}") + : new File("sym/${configuration}-${outputPath}") + + first.outputPath == file where: simulator | configuration | type | outputPath - false | "debug" | Type.iOS | "sym/debug-iphoneos" - false | "release" | Type.iOS | "sym/release-iphoneos" - true | "debug" | Type.iOS | "sym/debug-iphonesimulator" - true | "release" | Type.iOS | "sym/release-iphonesimulator" - false | "release" | Type.macOS | "sym/release" + false | "debug" | Type.iOS | Destination.IPHONE_OS + false | "release" | Type.iOS | Destination.IPHONE_OS + true | "debug" | Type.iOS | Destination.IPHONE_SIMULATOR + true | "release" | Type.iOS | Destination.IPHONE_SIMULATOR + false | "release" | Type.macOS | "release" + false | "debug" | Type.tvOS | Destination.APPLE_TV_OS + false | "release" | Type.tvOS | Destination.APPLE_TV_OS + true | "debug" | Type.tvOS | Destination.APPLE_TV_SIMULATOR + true | "release" | Type.tvOS | Destination.APPLE_TV_SIMULATOR } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 6e83294a..f598548c 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -110,8 +110,6 @@ class XcodeBuildPluginExtension { HashMap projectSettings = new HashMap<>() - - /** * internal parameters */ @@ -249,7 +247,6 @@ class XcodeBuildPluginExtension { } - void setArch(Object arch) { if (arch instanceof List) { logger.debug("Arch is List: " + arch + " - " + arch.getClass().getName()) @@ -278,7 +275,7 @@ class XcodeBuildPluginExtension { if (index == -1) { this.environment.put(environmentString, null) } else { - this.environment.put(environmentString.substring(0, index),environmentString.substring(index + 1)) + this.environment.put(environmentString.substring(0, index), environmentString.substring(index + 1)) } } } @@ -327,24 +324,23 @@ class XcodeBuildPluginExtension { return bundleName } - // should be removed an replaced by the xcodebuildParameters.outputPath File getOutputPath() { String path = getConfiguration() if (type == Type.iOS) { if (simulator) { - path += "-iphonesimulator" + path += Destination.IPHONE_SIMULATOR } else { - path += "-iphoneos" + path += Destination.IPHONE_OS } } else if (type == Type.tvOS) { if (simulator) { - path += "-appletvsimulator" + path += Destination.APPLE_TV_SIMULATOR } else { - path += "-appletvos" + path += Destination.APPLE_TV_OS } } - return new File(getSymRoot(), path) + return new File(getSymRoot(), "-" + path) } @@ -427,8 +423,6 @@ class XcodeBuildPluginExtension { } - - void setType(String type) { this.type = Type.typeFromString(type) } @@ -475,11 +469,10 @@ class XcodeBuildPluginExtension { xcode = new Xcode(commandRunner, xcodeVersion) } logger.debug("using xcode {}", xcode) - return xcode + return xcode } - XcodebuildParameters getXcodebuildParameters() { def result = new XcodebuildParameters() result.scheme = this.scheme @@ -506,4 +499,4 @@ class XcodeBuildPluginExtension { return result } -} \ No newline at end of file +} From 4af51d0457fc4afb66f57959e94fcf1b137030a4 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 16:45:43 +0100 Subject: [PATCH 014/121] Revert for now --- .../SimulatorControlSpecification.groovy | 194 +++++++++--------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 7cbeff76..2adf3209 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -20,14 +20,14 @@ class SimulatorControlSpecification extends Specification { final String SIM_CTL_LIST_UNAVAILABLE = "src/test/Resource/simctl-list-unavailable.txt" private static final String RES_PATH = "src/test/Resource" - private static final String SIM_CTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" + private static final String SIMCTL = "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" private static final String SIM_CTL_LIST_XCODE7 = "${RES_PATH}/simctl-list-xcode7.txt" private static final String SIM_CTL_LIST_XCODE8 = "${RES_PATH}/simctl-list-xcode8.txt" private static final String SIM_CTL_LIST_XCODE9 = "${RES_PATH}/simctl-list-xcode9.txt" private static final String SIM_CTL_LIST_XCODE9_1 = "${RES_PATH}/simctl-list-xcode9_1.txt" def setup() { - xcode.getSimctl() >> SIM_CTL + xcode.getSimctl() >> SIMCTL xcode.getPath() >> "/Applications/Xcode.app" simulatorControl = new SimulatorControl(commandRunner, xcode) } @@ -57,7 +57,7 @@ class SimulatorControlSpecification extends Specification { } void mockWithFile(String uri) { - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File(uri)) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File(uri)) } @@ -102,7 +102,7 @@ class SimulatorControlSpecification extends Specification { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.iOS) @@ -116,7 +116,7 @@ class SimulatorControlSpecification extends Specification { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.tvOS) @@ -198,22 +198,22 @@ class SimulatorControlSpecification extends Specification { simulatorControl.deleteAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) - 1 * commandRunner.runWithResult([SIM_CTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "15F68098-3B21-411D-B553-1C3161C100E7"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "454F3900-7B07-422E-A731-D46C821888B5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "B8278DAC-97EE-4097-88CA-5650960882A5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "0560469A-813F-4AF7-826C-4598802A7FFD"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "5C4434E1-81AC-4448-8237-26029A57E594"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "29C34492-7006-41D7-B634-8703972F725C"]) + 1 * commandRunner.runWithResult([SIMCTL, "delete", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) } @@ -225,26 +225,26 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-7-1"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPhone", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Resizable iPad", "com.apple.CoreSimulator.SimDeviceType.Resizable-iPad", "com.apple.CoreSimulator.SimRuntime.iOS-8-2"]) } @@ -257,22 +257,22 @@ class SimulatorControlSpecification extends Specification { simulatorControl.eraseAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "15F68098-3B21-411D-B553-1C3161C100E7"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "454F3900-7B07-422E-A731-D46C821888B5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "B8278DAC-97EE-4097-88CA-5650960882A5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "0560469A-813F-4AF7-826C-4598802A7FFD"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "5C4434E1-81AC-4448-8237-26029A57E594"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "29C34492-7006-41D7-B634-8703972F725C"]) - 1 * commandRunner.runWithResult([SIM_CTL, "erase", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "73C126C8-FD53-44EA-80A3-84F5F19508C0"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "15F68098-3B21-411D-B553-1C3161C100E7"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "545260B4-C6B8-4D3A-9348-AD3B882D8D17"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "454F3900-7B07-422E-A731-D46C821888B5"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "F60A8735-97D9-48A8-9728-3CC53394F7FC"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "B8278DAC-97EE-4097-88CA-5650960882A5"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "E06E8144-D4AB-4616-A19E-9A489FB0CC17"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "0560469A-813F-4AF7-826C-4598802A7FFD"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "F029A31F-3CBF-422D-AEF4-D05675BAEDEF"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "6F2558A0-A789-443B-B142-7BA707E3C9E8"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "075026D3-C77E-40F9-944C-EBCB565E17D5"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "5C4434E1-81AC-4448-8237-26029A57E594"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "E85B0A4D-6B82-4F7C-B4CF-3C00E4EFF3D1"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "A7400DB8-CDF3-4E6F-AF87-EB2B296D82C5"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "29C34492-7006-41D7-B634-8703972F725C"]) + 1 * commandRunner.runWithResult([SIMCTL, "erase", "50D9CBF1-608C-4866-9B5F-234D7FACBC16"]) } @@ -315,7 +315,7 @@ class SimulatorControlSpecification extends Specification { def "devices iOS9.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List runtimes = simulatorControl.getRuntimes() @@ -342,20 +342,20 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 4s", "com.apple.CoreSimulator.SimDeviceType.iPhone-4s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-9-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-2-0"]) } @@ -367,8 +367,8 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "pair", "86895139-2FA4-4E97-A91A-C088A02F7BCD", "FE4BE76C-A3A1-4FB0-8BD4-7B87B4ACEDB2"]) - 1 * commandRunner.runWithResult([SIM_CTL, "pair", "2A40D83C-EF8E-46AB-9C50-7DA01DA0B01F", "6F866EE0-55E8-439C-95F4-3FF19DAF553F"]) + 1 * commandRunner.runWithResult([SIMCTL, "pair", "86895139-2FA4-4E97-A91A-C088A02F7BCD", "FE4BE76C-A3A1-4FB0-8BD4-7B87B4ACEDB2"]) + 1 * commandRunner.runWithResult([SIMCTL, "pair", "2A40D83C-EF8E-46AB-9C50-7DA01DA0B01F", "6F866EE0-55E8-439C-95F4-3FF19DAF553F"]) } @@ -414,7 +414,7 @@ class SimulatorControlSpecification extends Specification { def "get 8.4 device for destination xcode 7.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) Destination destination = new Destination() destination.name = "iPad 2" destination.platform = 'iOS Simulator' @@ -431,7 +431,7 @@ class SimulatorControlSpecification extends Specification { def "get 9.1 device for destination xcode 7.1"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) Destination destination = new Destination() destination.name = "iPad 2" destination.platform = 'iOS Simulator' @@ -449,7 +449,7 @@ class SimulatorControlSpecification extends Specification { def "get all iOS simulator destinations"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List allDestinations = simulatorControl.getAllDestinations(Type.iOS) @@ -465,7 +465,7 @@ class SimulatorControlSpecification extends Specification { def "get all iOS simulator destinations of runtime"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) SimulatorRuntime runtime = simulatorControl.getMostRecentRuntime(Type.iOS) when: @@ -481,7 +481,7 @@ class SimulatorControlSpecification extends Specification { def "get all tvOS simulator destinations"() { given: commandRunner.runWithResult(["/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun", "-sdk", "iphoneos", "-find", "simctl"]) >> "/Applications/Xcode.app/Contents/Developer/usr/bin/simctl" - commandRunner.runWithResult([SIM_CTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) + commandRunner.runWithResult([SIMCTL, "list"]) >> FileUtils.readFileToString(new File("src/test/Resource/simctl-list-xcode7_1.txt")) when: List allDestinations = simulatorControl.getAllDestinations(Type.tvOS) @@ -572,33 +572,33 @@ class SimulatorControlSpecification extends Specification { simulatorControl.createAll() then: - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Pro (9.7-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPad Pro (12.9-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5", "com.apple.CoreSimulator.SimDeviceType.iPhone-5", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 5s", "com.apple.CoreSimulator.SimDeviceType.iPhone-5s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6", "com.apple.CoreSimulator.SimDeviceType.iPhone-6", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 6s", "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad 2", "com.apple.CoreSimulator.SimDeviceType.iPad-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Retina", "com.apple.CoreSimulator.SimDeviceType.iPad-Retina", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air", "com.apple.CoreSimulator.SimDeviceType.iPad-Air", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Air 2", "com.apple.CoreSimulator.SimDeviceType.iPad-Air-2", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Pro (9.7-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPad Pro (12.9-inch)", "com.apple.CoreSimulator.SimDeviceType.iPad-Pro", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 7 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "iPhone 7", "com.apple.CoreSimulator.SimDeviceType.iPhone-7", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 7 Plus", "com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "iPhone 7", "com.apple.CoreSimulator.SimDeviceType.iPhone-7", "com.apple.CoreSimulator.SimRuntime.iOS-10-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch Series 2 - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple Watch Series 2 - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch Series 2 - 38mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple Watch Series 2 - 42mm", "com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm", "com.apple.CoreSimulator.SimRuntime.watchOS-3-0"]) - 1 * commandRunner.runWithResult([SIM_CTL, "create", "Apple TV 1080p", "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p", "com.apple.CoreSimulator.SimRuntime.tvOS-10-0"]) + 1 * commandRunner.runWithResult([SIMCTL, "create", "Apple TV 1080p", "com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p", "com.apple.CoreSimulator.SimRuntime.tvOS-10-0"]) } From 3e1eb4a5d5b12da13b813002446c56acf9658898 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 17:45:47 +0100 Subject: [PATCH 015/121] Extract the path helper, should be done for all paths resolution --- .../org/openbakery/util/PathHelper.groovy | 71 +++++++++++++++++++ .../org/openbakery/xcode/Destination.groovy | 26 +++---- .../xcode/XcodebuildParameters.groovy | 18 +++-- .../org/openbakery/util/PathHelperTest.groovy | 46 ++++++++++++ .../XcodebuildParametersSpecification.groovy | 17 ++--- 5 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy create mode 100644 libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy new file mode 100644 index 00000000..1ece03e6 --- /dev/null +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -0,0 +1,71 @@ +package org.openbakery.util + +import org.openbakery.xcode.Type + +class PathHelper { + public static final String APPLE_TV_OS = "appletvos" + public static final String APPLE_TV_SIMULATOR = "appletvsimulator" + public static final String IPHONE_SIMULATOR = "iphonesimulator" + public static final String IPHONE_OS = "iphoneos" + + static File resolvePath(Type type, + boolean simulator, + File symRoot, + String configuration) { + File result + switch (type) { + case Type.iOS: + result = resolveIosSymRoot(simulator, + symRoot, + configuration) + break + + case Type.tvOS: + result = resolveAppleTvSymRoot(simulator, + symRoot, + configuration) + break + + case Type.macOS: + result = resolveMacOsSymRoot(symRoot, + configuration) + break + + default: + throw new IllegalStateException("WatchOs not implemeted") + break + + } + + return result + } + + static File resolveAppleTvSymRoot(boolean simulator, + File symRoot, + String configuration) { + return resolveSymRoot(symRoot, + configuration, + simulator ? APPLE_TV_SIMULATOR : APPLE_TV_OS) + } + + static File resolveIosSymRoot(boolean simulator, + File symRoot, + String configuration) { + return resolveSymRoot(symRoot, + configuration, + simulator ? IPHONE_SIMULATOR : IPHONE_OS) + } + + static File resolveMacOsSymRoot(File symRoot, + String configuration) { + return new File(symRoot, + configuration) + } + + private static File resolveSymRoot(File symRoot, + String configuration, + String destination) { + return new File(symRoot, + "${configuration}-${destination}") + } +} diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy index de42fafe..95ef42b0 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Destination.groovy @@ -5,6 +5,7 @@ import org.apache.commons.lang.StringUtils /* * User: rene */ + class Destination { String platform = null @@ -13,11 +14,6 @@ class Destination { String id = null String os = null - public static final String APPLE_TV_OS = "appletvos" - public static final String APPLE_TV_SIMULATOR = "appletvsimulator" - public static final String IPHONE_SIMULATOR = "iphonesimulator" - public static final String IPHONE_OS = "iphoneos" - Destination() { } @@ -32,18 +28,18 @@ class Destination { } public Type getTargetType() { - return Type.typeFromString(platform) + return Type.typeFromString(platform) } @Override public String toString() { return "Destination{" + - "platform='" + platform + '\'' + - ", name='" + name + '\'' + - ", arch='" + arch + '\'' + - ", id='" + id + '\'' + - ", os='" + os + '\'' + - '}'; + "platform='" + platform + '\'' + + ", name='" + name + '\'' + + ", arch='" + arch + '\'' + + ", id='" + id + '\'' + + ", os='" + os + '\'' + + '}'; } boolean equals(other) { @@ -57,9 +53,9 @@ class Destination { } if (StringUtils.equalsIgnoreCase(arch, otherDestination.arch) && - StringUtils.equalsIgnoreCase(name, otherDestination.name) && - StringUtils.equalsIgnoreCase(os, otherDestination.os) && - StringUtils.equalsIgnoreCase(platform, otherDestination.platform)) { + StringUtils.equalsIgnoreCase(name, otherDestination.name) && + StringUtils.equalsIgnoreCase(os, otherDestination.os) && + StringUtils.equalsIgnoreCase(platform, otherDestination.platform)) { return true } return false diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy index c9116eeb..6fc6d8cb 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/XcodebuildParameters.groovy @@ -1,6 +1,7 @@ package org.openbakery.xcode import org.apache.commons.io.FilenameUtils +import org.openbakery.util.PathHelper import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -141,18 +142,15 @@ class XcodebuildParameters { File getOutputPath() { if (type == Type.iOS) { - return resolveSymRoot(simulator - ? Destination.IPHONE_SIMULATOR - : Destination.IPHONE_OS) + return PathHelper.resolveIosSymRoot(simulator, + symRoot, + configuration) } else if (type == Type.tvOS) { - return resolveSymRoot(simulator - ? Destination.APPLE_TV_SIMULATOR - : Destination.APPLE_TV_OS) + return PathHelper.resolveAppleTvSymRoot(simulator, + symRoot, + configuration) } - return new File(getSymRoot(), configuration) - } - private File resolveSymRoot(String destination) { - return new File(getSymRoot(), "${configuration}-" + destination) + return PathHelper.resolveMacOsSymRoot(symRoot, configuration) } } diff --git a/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy new file mode 100644 index 00000000..7baeee5c --- /dev/null +++ b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy @@ -0,0 +1,46 @@ +package org.openbakery.util + +import org.openbakery.xcode.Type +import spock.lang.Specification + +class PathHelperTest extends Specification { + def "test iOS and TvOS symroot path resolution"() { + setup: + File tempSymRoot = File.createTempDir() + + expect: + File file = PathHelper.resolvePath(type, + simulator, + tempSymRoot, + configuration) + + file == new File(tempSymRoot, "${configuration}-${outputPath}") + + where: + simulator | configuration | type | outputPath + false | "debug" | Type.iOS | PathHelper.IPHONE_OS + false | "release" | Type.iOS | PathHelper.IPHONE_OS + true | "debug" | Type.iOS | PathHelper.IPHONE_SIMULATOR + true | "release" | Type.iOS | PathHelper.IPHONE_SIMULATOR + false | "debug" | Type.tvOS | PathHelper.APPLE_TV_OS + false | "release" | Type.tvOS | PathHelper.APPLE_TV_OS + true | "debug" | Type.tvOS | PathHelper.APPLE_TV_SIMULATOR + true | "release" | Type.tvOS | PathHelper.APPLE_TV_SIMULATOR + } + + def "Osx symroot path resolution"() { + setup: + File tempSymRoot = File.createTempDir() + + expect: + File file = PathHelper.resolveMacOsSymRoot(tempSymRoot, + configuration) + + file == new File(tempSymRoot, configuration) + + where: + configuration | outputPath + "debug" | _ + "release" | _ + } +} diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy index 04f1269d..40a2f4af 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/XcodebuildParametersSpecification.groovy @@ -1,5 +1,6 @@ package org.openbakery.xcode +import org.openbakery.util.PathHelper import spock.lang.Specification import spock.lang.Unroll @@ -190,15 +191,15 @@ class XcodebuildParametersSpecification extends Specification { where: simulator | configuration | type | outputPath - false | "debug" | Type.iOS | Destination.IPHONE_OS - false | "release" | Type.iOS | Destination.IPHONE_OS - true | "debug" | Type.iOS | Destination.IPHONE_SIMULATOR - true | "release" | Type.iOS | Destination.IPHONE_SIMULATOR + false | "debug" | Type.iOS | PathHelper.IPHONE_OS + false | "release" | Type.iOS | PathHelper.IPHONE_OS + true | "debug" | Type.iOS | PathHelper.IPHONE_SIMULATOR + true | "release" | Type.iOS | PathHelper.IPHONE_SIMULATOR false | "release" | Type.macOS | "release" - false | "debug" | Type.tvOS | Destination.APPLE_TV_OS - false | "release" | Type.tvOS | Destination.APPLE_TV_OS - true | "debug" | Type.tvOS | Destination.APPLE_TV_SIMULATOR - true | "release" | Type.tvOS | Destination.APPLE_TV_SIMULATOR + false | "debug" | Type.tvOS | PathHelper.APPLE_TV_OS + false | "release" | Type.tvOS | PathHelper.APPLE_TV_OS + true | "debug" | Type.tvOS | PathHelper.APPLE_TV_SIMULATOR + true | "release" | Type.tvOS | PathHelper.APPLE_TV_SIMULATOR } } From 72ed8d6f0f3de683ce37a92283fe931cd0569d85 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 11 Apr 2018 17:49:34 +0100 Subject: [PATCH 016/121] Fix typo --- .../openbakery/simulators/SimulatorControlSpecification.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 2adf3209..2424341e 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -647,7 +647,7 @@ class SimulatorControlSpecification extends Specification { } @Unroll - def "Ensure than the compilation runtime: #runtimeType with name : #runtimeName and #deviceCount devices is properly defined"() { + def "Ensure that the compilation runtime: #runtimeType with name : #runtimeName and #deviceCount devices is properly defined"() { expect: mockWithFile(ctlFile) From 27830bd1b9421fbadc8abb7971ef211a87820ef4 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 12 Apr 2018 15:54:15 +0100 Subject: [PATCH 017/121] Fix the tvos target --- .../bundle/ApplicationBundle.groovy | 8 ++++---- .../org/openbakery/codesign/Codesign.groovy | 13 ++++++------ .../org/openbakery/util/PathHelper.groovy | 2 ++ .../xcode/DestinationResolver.groovy | 3 ++- .../org/openbakery/util/PathHelperTest.groovy | 2 ++ plugin/build.gradle | 7 ++++--- .../XcodeBuildPluginExtension.groovy | 20 ++++++++----------- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/bundle/ApplicationBundle.groovy b/libxcode/src/main/groovy/org/openbakery/bundle/ApplicationBundle.groovy index 0804c675..2ece258e 100644 --- a/libxcode/src/main/groovy/org/openbakery/bundle/ApplicationBundle.groovy +++ b/libxcode/src/main/groovy/org/openbakery/bundle/ApplicationBundle.groovy @@ -19,7 +19,7 @@ public class ApplicationBundle { addPluginsToAppBundle(applicationPath, bundles) - if (isDeviceBuildOf(Type.iOS)) { + if (isDeviceBuildOf(Type.iOS) || isDeviceBuildOf(Type.tvOS)) { addWatchToAppBundle(applicationPath, bundles) } bundles.add(applicationPath) @@ -28,9 +28,9 @@ public class ApplicationBundle { private void addPluginsToAppBundle(File appBundle, ArrayList bundles) { File plugins - if (isDeviceBuildOf(Type.iOS)) { + if (isDeviceBuildOf(Type.iOS) || isDeviceBuildOf(Type.tvOS)) { plugins = new File(appBundle, "PlugIns") - } else if (this.type == Type.macOS) { + } else if (this.type == Type.macOS) { plugins = new File(appBundle, "Contents/PlugIns") } else { return @@ -43,7 +43,7 @@ public class ApplicationBundle { if (pluginBundle.name.endsWith(".framework")) { // Frameworks have to be signed with this path bundles.add(new File(pluginBundle, "/Versions/Current")) - } else if (pluginBundle.name.endsWith(".appex")) { + } else if (pluginBundle.name.endsWith(".appex")) { for (File appexBundle : pluginBundle.listFiles()) { if (appexBundle.isDirectory() && appexBundle.name.endsWith(".app")) { diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/Codesign.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/Codesign.groovy index c53163af..c1ccda77 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/Codesign.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/Codesign.groovy @@ -104,7 +104,7 @@ class Codesign { private void codeSignFrameworks(File bundle) { File frameworksDirectory - if (codesignParameters.type == Type.iOS) { + if (codesignParameters.type == Type.iOS || codesignParameters.type == Type.tvOS) { frameworksDirectory = new File(bundle, "Frameworks") } else { frameworksDirectory = new File(bundle, "Contents/Frameworks") @@ -130,7 +130,7 @@ class Codesign { if (codesignParameters.signingIdentity == null) { performCodesignWithoutIdentity(bundle) } else { - performCodesignWithIdentity(bundle,entitlements) + performCodesignWithIdentity(bundle, entitlements) } } @@ -178,7 +178,7 @@ class Codesign { private String getIdentifierForBundle(File bundle) { File infoPlist - if (codesignParameters.type == Type.iOS) { + if (codesignParameters.type == Type.iOS || codesignParameters.type == Type.tvOS) { infoPlist = new File(bundle, "Info.plist"); } else { infoPlist = new File(bundle, "Contents/Info.plist") @@ -190,7 +190,8 @@ class Codesign { ProvisioningProfileReader createProvisioningProfileReader(String bundleIdentifier, File provisionFile) { if (provisionFile == null) { - if (codesignParameters.type == Type.iOS) { + if (codesignParameters.type == Type.iOS + || codesignParameters.type == Type.tvOS) { throw new IllegalStateException("No provisioning profile found for bundle identifier: " + bundleIdentifier) } // on OS X this is valid @@ -235,7 +236,7 @@ class Codesign { File getXcentFile(File bundle) { def fileList = bundle.list( - [accept: { d, f -> f ==~ /.*xcent/ }] as FilenameFilter + [accept: { d, f -> f ==~ /.*xcent/ }] as FilenameFilter ) if (fileList == null || fileList.toList().isEmpty()) { return null @@ -254,7 +255,7 @@ class Codesign { applicationPrefix = applicationPrefix + "." logger.info("using application prefix: {}", applicationPrefix) - List keychainAccessGroups = configuration.getStringArray("keychain-access-groups") + List keychainAccessGroups = configuration.getStringArray("keychain-access-groups") logger.info("keychain-access-group from configuration: {}", result) keychainAccessGroups.each { item -> diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index 1ece03e6..53d5f3e9 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -1,7 +1,9 @@ package org.openbakery.util +import groovy.transform.CompileStatic import org.openbakery.xcode.Type +@CompileStatic class PathHelper { public static final String APPLE_TV_OS = "appletvos" public static final String APPLE_TV_SIMULATOR = "appletvsimulator" diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy index a7c8dc1d..870cc36f 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy @@ -16,7 +16,8 @@ class DestinationResolver { List allFor(XcodebuildParameters parameters) { - if (parameters.type == Type.iOS && !parameters.simulator) { + if ((parameters.type == Type.iOS || parameters.type == Type.tvOS) + && !parameters.simulator) { return [] } return simulatorControl.getAllDestinations(parameters.type) diff --git a/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy index 7baeee5c..256335d8 100644 --- a/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy +++ b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy @@ -14,6 +14,8 @@ class PathHelperTest extends Specification { tempSymRoot, configuration) + println "${configuration}-${outputPath}" + file == new File(tempSymRoot, "${configuration}-${outputPath}") where: diff --git a/plugin/build.gradle b/plugin/build.gradle index f48deec6..b5ec7d39 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -15,11 +15,12 @@ if (project.hasProperty("publishURL")) { if (project.hasProperty("publishUser")) { publishUser = project.publishUser } + if (project.hasProperty("publishPassword")) { publishPassword = project.publishPassword } - +println "publishUser :" + publishUser cobertura.coverageFormats = ['html', 'xml'] @@ -65,11 +66,11 @@ uploadArchives { repositories { mavenDeployer { configuration = configurations.deployerJars - + repository(url: publishURL) { authentication(userName: publishUser, password: publishPassword) } - + pom.project { licenses { license { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index f598548c..51efa3b3 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -20,17 +20,13 @@ import org.apache.commons.lang.StringUtils import org.gradle.api.Project import org.gradle.util.ConfigureUtil import org.openbakery.signing.Signing -import org.openbakery.xcode.Destination -import org.openbakery.xcode.Devices -import org.openbakery.xcode.Type -import org.openbakery.xcode.Xcode -import org.openbakery.xcode.XcodebuildParameters +import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper import org.openbakery.util.VariableResolver +import org.openbakery.xcode.* import org.slf4j.Logger import org.slf4j.LoggerFactory - /* ^ @@ -326,21 +322,21 @@ class XcodeBuildPluginExtension { // should be removed an replaced by the xcodebuildParameters.outputPath File getOutputPath() { - String path = getConfiguration() + String path = getConfiguration() + "-" if (type == Type.iOS) { if (simulator) { - path += Destination.IPHONE_SIMULATOR + path += PathHelper.IPHONE_SIMULATOR } else { - path += Destination.IPHONE_OS + path += PathHelper.IPHONE_OS } } else if (type == Type.tvOS) { if (simulator) { - path += Destination.APPLE_TV_SIMULATOR + path += PathHelper.APPLE_TV_SIMULATOR } else { - path += Destination.APPLE_TV_OS + path += PathHelper.APPLE_TV_OS } } - return new File(getSymRoot(), "-" + path) + return new File(getSymRoot(), path) } From 5c483ba868db8639bbc45f4107abfbcad5f28bd2 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 12 Apr 2018 15:55:28 +0100 Subject: [PATCH 018/121] Remove the test trace --- .../src/test/groovy/org/openbakery/util/PathHelperTest.groovy | 2 -- 1 file changed, 2 deletions(-) diff --git a/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy index 256335d8..7baeee5c 100644 --- a/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy +++ b/libxcode/src/test/groovy/org/openbakery/util/PathHelperTest.groovy @@ -14,8 +14,6 @@ class PathHelperTest extends Specification { tempSymRoot, configuration) - println "${configuration}-${outputPath}" - file == new File(tempSymRoot, "${configuration}-${outputPath}") where: From 3dbd6e9a5b0ea6c494bf9742f5fb6efb15f97f65 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 12 Apr 2018 15:56:03 +0100 Subject: [PATCH 019/121] Remove the test trace --- plugin/build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index b5ec7d39..fc1ff613 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -20,8 +20,6 @@ if (project.hasProperty("publishPassword")) { publishPassword = project.publishPassword } -println "publishUser :" + publishUser - cobertura.coverageFormats = ['html', 'xml'] apply plugin: 'maven' From 11553a80d5ee0e6e344ab15211a4e0b1ce969269 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 16 Apr 2018 14:31:21 +0100 Subject: [PATCH 020/121] Refactoring of the SimulatorControl in progress --- .../simulators/SimulatorControl.groovy | 21 +++++---------- .../SimulatorControlSpecification.groovy | 21 ++++++++------- .../simulators/SimulatorStartTask.groovy | 27 +++++++++---------- .../SimulatorStartTaskSpecification.groovy | 2 +- 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index 8a569f4c..2c5838ad 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -215,24 +215,17 @@ class SimulatorControl { } - SimulatorRuntime getRuntime(Destination destination) { - return getRuntimes() + Optional getRuntime(Destination destination) { + return Optional.ofNullable(getRuntimes() .findAll { it.type == destination.targetType } .findAll { it.version?.equals(new Version(destination.os)) } - .find() + .find()) } - SimulatorDevice getDevice(Destination destination) { - SimulatorRuntime runtime = getRuntime(destination) - if (runtime != null) { - - for (SimulatorDevice device in getDevices(runtime)) { - if (device.name.equalsIgnoreCase(destination.name)) { - return device - } - } - } - return null + Optional getDevice(final Destination destination) { + return getRuntime(destination) + .map { runtime -> getDevices(runtime) + .find { device -> device.name.equalsIgnoreCase(destination.name) } } } SimulatorDevice getDeviceWithIdentifier(String identifier) { diff --git a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy index 2424341e..7c45b25f 100644 --- a/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/simulators/SimulatorControlSpecification.groovy @@ -404,11 +404,12 @@ class SimulatorControlSpecification extends Specification { destination.os = '9.0' when: - SimulatorDevice device = simulatorControl.getDevice(destination) + Optional device = simulatorControl.getDevice(destination) then: - device.name == "iPhone 4s" - device.identifier == "5C8E1FF3-47B7-48B8-96E9-A12740DBC58A" + device.present + device.get().name == "iPhone 4s" + device.get().identifier == "5C8E1FF3-47B7-48B8-96E9-A12740DBC58A" } def "get 8.4 device for destination xcode 7.1"() { @@ -421,11 +422,12 @@ class SimulatorControlSpecification extends Specification { destination.os = '8.4' when: - SimulatorDevice device = simulatorControl.getDevice(destination) + Optional device = simulatorControl.getDevice(destination) then: - device.name == "iPad 2" - device.identifier == "E5089648-1CE4-40D5-8295-8E026BDDFF52" + device.present + device.get().name == "iPad 2" + device.get().identifier == "E5089648-1CE4-40D5-8295-8E026BDDFF52" } def "get 9.1 device for destination xcode 7.1"() { @@ -438,11 +440,12 @@ class SimulatorControlSpecification extends Specification { destination.os = '9.1' when: - SimulatorDevice device = simulatorControl.getDevice(destination) + Optional device = simulatorControl.getDevice(destination) then: - device.name == "iPad 2" - device.identifier == "D72F7CC6-8426-4E0A-A234-34747B1F30DD" + device.present + device.get().name == "iPad 2" + device.get().identifier == "D72F7CC6-8426-4E0A-A234-34747B1F30DD" } diff --git a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy index 04965749..e166a9f8 100644 --- a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy @@ -2,26 +2,25 @@ package org.openbakery.simulators import org.gradle.api.tasks.TaskAction import org.openbakery.xcode.Destination -import org.openbakery.XcodePlugin class SimulatorStartTask extends AbstractSimulatorTask { - public SimulatorStartTask() { - setDescription("Start iOS Simulators") - } + public SimulatorStartTask() { + setDescription("Start iOS Simulators") + } + @TaskAction + void run() { - @TaskAction - void run() { + Destination destination = getDestination() - Destination destination = getDestination() - - SimulatorDevice device = simulatorControl.getDevice(destination) - - simulatorControl.killAll() - simulatorControl.runDevice(device) - simulatorControl.waitForDevice(device) - } + Optional device = simulatorControl.getDevice(destination) + if (device.present) { + simulatorControl.killAll() + simulatorControl.runDevice(device) + simulatorControl.waitForDevice(device) + } + } } diff --git a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy index 6ad50d8b..10d591c0 100644 --- a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy @@ -65,7 +65,7 @@ class SimulatorStartTaskSpecification extends Specification { def "run"() { given: - simulatorControl.getDevice(_) >> devices9_1[0] + simulatorControl.getDevice(_) >> Optional.ofNullable(devices9_1[0]) destinationResolver.getDestinations(_) >> destinations when: From 66c81ccc748bc9fccbd1a2a5fe6de3c95f3c9a88 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 17 Apr 2018 15:25:05 +0100 Subject: [PATCH 021/121] --wip-- [skip ci] --- build.gradle | 2 +- .../simulators/SimulatorControl.groovy | 7 ++-- .../SimulatorStartTaskSpecification.groovy | 36 +++++++++---------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index 20266602..00092018 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ allprojects { apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' - def versionNumber = "0.15.2" + def versionNumber = "0.2.6-SNAPSHOT" if (project.hasProperty("versionNumber")) { versionNumber = project.versionNumber diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index 2c5838ad..40a18300 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -1,5 +1,6 @@ package org.openbakery.simulators +import groovy.transform.CompileStatic import org.openbakery.CommandRunner import org.openbakery.CommandRunnerException import org.openbakery.xcode.Destination @@ -9,6 +10,7 @@ import org.openbakery.xcode.Xcode import org.slf4j.Logger import org.slf4j.LoggerFactory +@CompileStatic class SimulatorControl { @@ -128,7 +130,7 @@ class SimulatorControl { } SimulatorDevice parseIdentifierFromDevicePairs(String line) { - def tokenizer = new StringTokenizer(line, "()"); + def tokenizer = new StringTokenizer(line, "()") if (tokenizer.hasMoreTokens()) { // ignore first token tokenizer.nextToken() @@ -189,7 +191,7 @@ class SimulatorControl { for (SimulatorRuntime runtime in getRuntimes()) { if (runtime.type == type) { - result.add(runtime); + result.add(runtime) } } Collections.sort(result, new SimulatorRuntimeComparator()) @@ -355,6 +357,7 @@ class SimulatorControl { } catch (CommandRunnerException ex) { // ignore, this exception means that no simulator was running } + try { commandRunner.run("killall", "Simulator") // for xcode 7 } catch (CommandRunnerException ex) { diff --git a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy index 10d591c0..40237eb0 100644 --- a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy @@ -19,29 +19,29 @@ class SimulatorStartTaskSpecification extends Specification { def devices9_1 = [ - new SimulatorDevice("iPhone 4s (8C8C43D3-B53F-4091-8D7C-6A4B38051389) (Shutdown)"), - new SimulatorDevice("iPhone 5 (2EEDED93-1568-4D46-84A2-6E2AE723ECC6) (Shutdown)"), - new SimulatorDevice("iPhone 5s (DE72B92C-D8E2-4CCE-A5E1-9174B6A03209) (Shutdown)"), - new SimulatorDevice("iPhone 6 (CD613910-6F4E-41A3-B0CB-1EBC16449F42) (Shutdown)"), - new SimulatorDevice("iPhone 6 Plus (364A3F52-DED2-4BBD-B40A-B0F3F374E51F) (Shutdown)"), - new SimulatorDevice("iPhone 6s (A3F2EB56-1EA8-4527-8BA3-BEE76AAB6D01) (Shutdown)"), - new SimulatorDevice("iPhone 6s Plus (3EACF222-830E-4BF1-ADB3-75E98AB99480) (Shutdown)"), - new SimulatorDevice("iPad 2 (D72F7CC6-8426-4E0A-A234-34747B1F30DD) (Shutdown)"), - new SimulatorDevice("iPad Retina (DAE7925F-8FC7-42B0-A1F0-7173C3F40114) (Shutdown)"), - new SimulatorDevice("iPad Air (4F432AFB-370C-4741-B7D7-803F3E223C36) (Shutdown)"), - new SimulatorDevice("iPad Air 2 (8064C333-D8F0-43A7-83B4-DFA79071A870) (Shutdown)"), - new SimulatorDevice("iPad Pro (744F7B28-373D-4666-B4DF-8438D1109663) (Shutdown)") + new SimulatorDevice("iPhone 4s (8C8C43D3-B53F-4091-8D7C-6A4B38051389) (Shutdown)"), + new SimulatorDevice("iPhone 5 (2EEDED93-1568-4D46-84A2-6E2AE723ECC6) (Shutdown)"), + new SimulatorDevice("iPhone 5s (DE72B92C-D8E2-4CCE-A5E1-9174B6A03209) (Shutdown)"), + new SimulatorDevice("iPhone 6 (CD613910-6F4E-41A3-B0CB-1EBC16449F42) (Shutdown)"), + new SimulatorDevice("iPhone 6 Plus (364A3F52-DED2-4BBD-B40A-B0F3F374E51F) (Shutdown)"), + new SimulatorDevice("iPhone 6s (A3F2EB56-1EA8-4527-8BA3-BEE76AAB6D01) (Shutdown)"), + new SimulatorDevice("iPhone 6s Plus (3EACF222-830E-4BF1-ADB3-75E98AB99480) (Shutdown)"), + new SimulatorDevice("iPad 2 (D72F7CC6-8426-4E0A-A234-34747B1F30DD) (Shutdown)"), + new SimulatorDevice("iPad Retina (DAE7925F-8FC7-42B0-A1F0-7173C3F40114) (Shutdown)"), + new SimulatorDevice("iPad Air (4F432AFB-370C-4741-B7D7-803F3E223C36) (Shutdown)"), + new SimulatorDevice("iPad Air 2 (8064C333-D8F0-43A7-83B4-DFA79071A870) (Shutdown)"), + new SimulatorDevice("iPad Pro (744F7B28-373D-4666-B4DF-8438D1109663) (Shutdown)") ] def destinations = [ - new Destination("iOS Simulator", "iPhone 4s", "iOS 9"), + new Destination("iOS Simulator", "iPhone 4s", "iOS 9"), ] def setup() { projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.apply plugin:org.openbakery.XcodePlugin + project.apply plugin: org.openbakery.XcodePlugin projectDir.mkdirs() @@ -73,9 +73,9 @@ class SimulatorStartTaskSpecification extends Specification { then: - 1 *simulatorControl.killAll() - 1 *simulatorControl.runDevice(devices9_1[0]) - 1 *simulatorControl.waitForDevice(devices9_1[0]) + 1 * simulatorControl.killAll() + 1 * simulatorControl.runDevice(devices9_1[0]) + 1 * simulatorControl.waitForDevice(devices9_1[0]) } @@ -93,7 +93,7 @@ class SimulatorStartTaskSpecification extends Specification { task.run() then: - 1 *simulatorControl.getDevice((Destination)_) >> { arguments -> + 1 * simulatorControl.getDevice((Destination) _) >> { arguments -> destination = arguments[0] return devices9_1[0] } From 07af21eebe1ef940d574f6d480b7d0f7a682b321 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 17 Apr 2018 15:43:37 +0100 Subject: [PATCH 022/121] Add the bootstrap task --- .../groovy/org/openbakery/XcodePlugin.groovy | 9 +- .../carthage/AbstractCarthageTaskBase.groovy | 89 +++++++++++++++++++ .../carthage/CarthageBootStrapTask.groovy | 32 +++++++ .../carthage/CarthageCleanTask.groovy | 2 - .../carthage/CarthageUpdateTask.groovy | 89 ++----------------- 5 files changed, 132 insertions(+), 89 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy create mode 100644 plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 4a8185c7..700850ec 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -27,6 +27,7 @@ import org.openbakery.appledoc.AppledocTask import org.openbakery.appstore.AppstorePluginExtension import org.openbakery.appstore.AppstoreValidateTask import org.openbakery.appstore.AppstoreUploadTask +import org.openbakery.carthage.CarthageBootStrapTask import org.openbakery.carthage.CarthageCleanTask import org.openbakery.carthage.CarthageUpdateTask import org.openbakery.cocoapods.CocoapodsBootstrapTask @@ -90,7 +91,7 @@ class XcodePlugin implements Plugin { public static final String XCODE_TEST_TASK_NAME = "xcodetest" public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" - public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" + public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" public static final String ARCHIVE_TASK_NAME = "archive" public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" @@ -129,6 +130,7 @@ class XcodePlugin implements Plugin { public static final String OCLINT_TASK_NAME = 'oclint' public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' public static final String CPD_TASK_NAME = 'cpd' + public static final String CARTHAGE_BOOTSTRAP_TASK_NAME = 'carthageBootstrap' public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' @@ -143,8 +145,6 @@ class XcodePlugin implements Plugin { public static final String SDK_IPHONESIMULATOR = "iphonesimulator" - - void apply(Project project) { project.getPlugins().apply(BasePlugin.class); @@ -597,6 +597,7 @@ class XcodePlugin implements Plugin { private void configureCarthage(Project project) { project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) + project.task(CARTHAGE_BOOTSTRAP_TASK_NAME, type: CarthageBootStrapTask, group: CARTHAGE_GROUP_NAME) } private configureCarthageDependencies(Project project) { @@ -614,7 +615,7 @@ class XcodePlugin implements Plugin { Task ocLintTask = project.getTasks().create(OCLINT_TASK_NAME); ocLintTask.group = ANALYTICS_GROUP_NAME - ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME + ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME ocLintTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)) XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XcodePlugin.XCODE_BUILD_TASK_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy new file mode 100644 index 00000000..5e36d2ae --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -0,0 +1,89 @@ +package org.openbakery.carthage + +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.* +import org.openbakery.AbstractXcodeTask +import org.openbakery.xcode.Type + +abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { + + static final String ACTION_BOOTSTRAP = "bootstrap" + static final String ACTION_UPDATE = "update" + static final String ARG_CACHE_BUILDS = "--cache-builds" + static final String ARG_PLATFORM = "--platform" + static final String CARTHAGE_FILE = "Cartfile" + static final String CARTHAGE_FILE_RESOLVED = "Cartfile.resolved" + static final String CARTHAGE_PLATFORM_IOS = "iOS" + static final String CARTHAGE_PLATFORM_MACOS = "Mac" + static final String CARTHAGE_PLATFORM_TVOS = "tvOS" + static final String CARTHAGE_PLATFORM_WATCHOS = "watchOS" + static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" + + AbstractCarthageTaskBase() { + super() + } + + @InputFile + @Optional + @PathSensitive(PathSensitivity.RELATIVE) + Provider getCartFile() { + // Cf https://github.com/gradle/gradle/issues/2016 + File file = project.rootProject.file(CARTHAGE_FILE) + return project.provider { + file.exists() ? file + : File.createTempFile(CARTHAGE_FILE, "") + } + } + + @InputFile + @Optional + @PathSensitive(PathSensitivity.RELATIVE) + Provider getCartResolvedFile() { + // Cf https://github.com/gradle/gradle/issues/2016 + File file = project.rootProject.file(CARTHAGE_FILE_RESOLVED) + return project.provider { + file.exists() ? file + : File.createTempFile(CARTHAGE_FILE_RESOLVED, "resolved") + } + } + + @Input + String getCarthagePlatformName() { + switch (project.xcodebuild.type) { + case Type.iOS: return CARTHAGE_PLATFORM_IOS + case Type.tvOS: return CARTHAGE_PLATFORM_TVOS + case Type.macOS: return CARTHAGE_PLATFORM_MACOS + case Type.watchOS: return CARTHAGE_PLATFORM_WATCHOS + default: return 'all' + } + } + + @OutputDirectory + Provider getOutputDirectory() { + return project.provider { + project.rootProject.file("Carthage/Build/" + getCarthagePlatformName()) + } + } + + String getCarthageCommand() { + try { + return commandRunner.runWithResult("which", "carthage") + } catch (CommandRunnerException) { + // ignore, because try again with full path below + } + + try { + commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) + return CARTHAGE_USR_BIN_PATH + } catch (CommandRunnerException) { + // ignore, because blow an exception is thrown + } + throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") + } + + boolean hasCartFile() { + return project.rootProject + .file(CARTHAGE_FILE) + .exists() + } +} diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy new file mode 100644 index 00000000..e8289369 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -0,0 +1,32 @@ +package org.openbakery.carthage + +import org.gradle.api.tasks.TaskAction +import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.openbakery.output.ConsoleOutputAppender + +class CarthageBootStrapTask extends AbstractCarthageTaskBase { + + CarthageBootStrapTask() { + super() + setDescription "Check out and build the Carthage project dependencies" + } + + @TaskAction + void update() { + if (hasCartFile()) { + logger.info('Boostrap Carthage for platform ' + carthagePlatformName) + + def output = services.get(StyledTextOutputFactory) + .create(CarthageBootStrapTask) + + commandRunner.run( + project.projectDir.absolutePath, + [getCarthageCommand(), + ACTION_BOOTSTRAP, + ARG_PLATFORM, + carthagePlatformName, + ARG_CACHE_BUILDS], + new ConsoleOutputAppender(output)) + } + } +} diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageCleanTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageCleanTask.groovy index 19ead8e6..43ec92e6 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageCleanTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageCleanTask.groovy @@ -14,6 +14,4 @@ class CarthageCleanTask extends DefaultTask { def clean() { project.file("Carthage").deleteDir() } - - } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageUpdateTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageUpdateTask.groovy index 60d38bf7..bc742f4a 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageUpdateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageUpdateTask.groovy @@ -1,71 +1,14 @@ package org.openbakery.carthage -import org.gradle.api.provider.Provider -import org.gradle.api.tasks.* +import org.gradle.api.tasks.TaskAction import org.gradle.internal.logging.text.StyledTextOutputFactory -import org.openbakery.AbstractXcodeTask import org.openbakery.output.ConsoleOutputAppender -import org.openbakery.xcode.Type -class CarthageUpdateTask extends AbstractXcodeTask { - - static final String ACTION_UPDATE = "update" - static final String ARG_CACHE_BUILDS = "--cache-builds" - static final String ARG_PLATFORM = "--platform" - static final String CARTHAGE_FILE = "Cartfile" - static final String CARTHAGE_FILE_RESOLVED = "Cartfile.resolved" - static final String CARTHAGE_PLATFORM_IOS = "iOS" - static final String CARTHAGE_PLATFORM_MACOS = "Mac" - static final String CARTHAGE_PLATFORM_TVOS = "tvOS" - static final String CARTHAGE_PLATFORM_WATCHOS = "watchOS" - static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" +class CarthageUpdateTask extends AbstractCarthageTaskBase { CarthageUpdateTask() { super() - newOutputDirectory() - setDescription "Installs the carthage dependencies for the given project" - } - - @InputFile - @Optional - @PathSensitive(PathSensitivity.RELATIVE) - Provider getCartFile() { - // Cf https://github.com/gradle/gradle/issues/2016 - File file = project.rootProject.file(CARTHAGE_FILE) - return project.provider { - file.exists() ? file - : File.createTempFile(CARTHAGE_FILE, "") - } - } - - @InputFile - @Optional - @PathSensitive(PathSensitivity.RELATIVE) - Provider getCartResolvedFile() { - // Cf https://github.com/gradle/gradle/issues/2016 - File file = project.rootProject.file(CARTHAGE_FILE_RESOLVED) - return project.provider { - file.exists() ? file - : File.createTempFile(CARTHAGE_FILE_RESOLVED, "resolved") - } - } - - @Input - String getCarthagePlatformName() { - switch (project.xcodebuild.type) { - case Type.iOS: return CARTHAGE_PLATFORM_IOS - case Type.tvOS: return CARTHAGE_PLATFORM_TVOS - case Type.macOS: return CARTHAGE_PLATFORM_MACOS - case Type.watchOS: return CARTHAGE_PLATFORM_WATCHOS - default: return 'all' - } - } - - @OutputDirectory - Provider getOutputDirectory() { - return project.provider { - project.rootProject.file("Carthage/Build/" + getCarthagePlatformName()) - } + setDescription "Update and rebuild the Carthage project dependencies" } @TaskAction @@ -73,7 +16,9 @@ class CarthageUpdateTask extends AbstractXcodeTask { if (hasCartFile()) { logger.info('Update Carthage for platform ' + carthagePlatformName) - def output = services.get(StyledTextOutputFactory).create(CarthageUpdateTask) + def output = services.get(StyledTextOutputFactory) + .create(CarthageUpdateTask) + commandRunner.run( project.projectDir.absolutePath, [getCarthageCommand(), @@ -84,26 +29,4 @@ class CarthageUpdateTask extends AbstractXcodeTask { new ConsoleOutputAppender(output)) } } - - String getCarthageCommand() { - try { - return commandRunner.runWithResult("which", "carthage") - } catch (CommandRunnerException) { - // ignore, because try again with full path below - } - - try { - commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) - return CARTHAGE_USR_BIN_PATH - } catch (CommandRunnerException) { - // ignore, because blow an exception is thrown - } - throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") - } - - boolean hasCartFile() { - return project.rootProject - .file(CARTHAGE_FILE) - .exists() - } } From 2d5d292ab947af2db59676e0a2a48c4f56212b35 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 17 Apr 2018 15:48:40 +0100 Subject: [PATCH 023/121] Replace the update task by the bootstrap one in the default process --- .../src/main/groovy/org/openbakery/XcodePlugin.groovy | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 700850ec..a7851c8e 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -601,12 +601,13 @@ class XcodePlugin implements Plugin { } private configureCarthageDependencies(Project project) { - CarthageUpdateTask carthageUpdateTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME) - CarthageCleanTask carthageCleanTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_CLEAN_TASK_NAME) + CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CARTHAGE_BOOTSTRAP_TASK_NAME) + if (bootStrapTask.hasCartFile()) { + addDependencyToBuild(project, bootStrapTask) - if (carthageUpdateTask.hasCartFile()) { - addDependencyToBuild(project, carthageUpdateTask) - project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(carthageCleanTask); + project.getTasks() + .getByName(BasePlugin.CLEAN_TASK_NAME) + .dependsOn(project.getTasks().getByName(CARTHAGE_CLEAN_TASK_NAME)) } } From d23fd215227647f2b0b8300878726e71fd121080 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 17 Apr 2018 16:25:27 +0100 Subject: [PATCH 024/121] Add unit tests --- .../carthage/CarthageBootStrapTaskTest.groovy | 121 ++++++++++++++++++ .../CarthageUpdateTaskSpecification.groovy | 2 +- 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy diff --git a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy new file mode 100644 index 00000000..47cd2036 --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy @@ -0,0 +1,121 @@ +package org.openbakery.carthage + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.ExpectedException +import org.openbakery.CommandRunner +import org.openbakery.output.ConsoleOutputAppender +import spock.lang.Specification +import spock.lang.Unroll + +import static org.openbakery.carthage.AbstractCarthageTaskBase.* +import static org.openbakery.xcode.Type.* + +class CarthageBootStrapTaskTest extends Specification { + + CarthageBootStrapTask subject + CommandRunner commandRunner = Mock(CommandRunner) + File projectDir + File cartFile + Project project + + @Rule + public ExpectedException exception = ExpectedException.none() + + void setup() { + projectDir = File.createTempDir() + + cartFile = new File(projectDir, "Cartfile") + cartFile << 'github "Alamofire/Alamofire"' + + project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + + project.buildDir = new File(projectDir, 'build').absoluteFile + project.apply plugin: org.openbakery.XcodePlugin + + subject = project.getTasks().getByPath('carthageBootstrap') + assert subject != null + + subject.commandRunner = commandRunner + } + + def "The carthage bootstrap task should be present"() { + expect: + subject instanceof CarthageBootStrapTask + } + + @Unroll + def "When bootstrap is executed should only update the platform: #platform"() { + given: + commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" + project.xcodebuild.type = platform + + when: + subject.update() + + then: + 1 * commandRunner.run(_, + [CARTHAGE_USR_BIN_PATH, + ACTION_BOOTSTRAP, + ARG_PLATFORM, + carthagePlatform, + ARG_CACHE_BUILDS] + , _) >> { + args -> args[2] instanceof ConsoleOutputAppender + } + + where: + platform | carthagePlatform + tvOS | CARTHAGE_PLATFORM_TVOS + macOS | CARTHAGE_PLATFORM_MACOS + watchOS | CARTHAGE_PLATFORM_WATCHOS + iOS | CARTHAGE_PLATFORM_IOS + } + + def "The task should not be executed if the 'Cartfile` file is missing"() { + given: + commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" + project.xcodebuild.type = platform + + when: + cartFile.delete() + subject.update() + + then: + 0 * commandRunner.run(_, [CARTHAGE_USR_BIN_PATH, + ACTION_UPDATE, + ARG_PLATFORM, + carthagePlatform, + ARG_CACHE_BUILDS], _) >> { + args -> args[2] instanceof ConsoleOutputAppender + } + + where: + platform | carthagePlatform + tvOS | CARTHAGE_PLATFORM_TVOS + macOS | CARTHAGE_PLATFORM_MACOS + watchOS | CARTHAGE_PLATFORM_WATCHOS + iOS | CARTHAGE_PLATFORM_IOS + } + + def "The subject output directory should be platform dependant"() { + when: + project.xcodebuild.type = platform + + then: + Provider outputDirectory = subject.outputDirectory + outputDirectory.isPresent() + outputDirectory.get().name == carthagePlatform + + where: + platform | carthagePlatform + tvOS | CARTHAGE_PLATFORM_TVOS + macOS | CARTHAGE_PLATFORM_MACOS + watchOS | CARTHAGE_PLATFORM_WATCHOS + iOS | CARTHAGE_PLATFORM_IOS + } +} diff --git a/plugin/src/test/groovy/org/openbakery/carthage/CarthageUpdateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/carthage/CarthageUpdateTaskSpecification.groovy index a0d2ca13..d5b43466 100644 --- a/plugin/src/test/groovy/org/openbakery/carthage/CarthageUpdateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/carthage/CarthageUpdateTaskSpecification.groovy @@ -23,7 +23,7 @@ class CarthageUpdateTaskSpecification extends Specification { CommandRunner commandRunner = Mock(CommandRunner) @Rule - public ExpectedException exception = ExpectedException.none(); + public ExpectedException exception = ExpectedException.none() def setup() { projectDir = File.createTempDir() From 43424723571fbc6aa33fc3a8b5c815fb2602b569 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 18 Apr 2018 14:03:57 +0100 Subject: [PATCH 025/121] --wip-- [skip ci] --- .../org/openbakery/CommandRunner.groovy | 28 ++++++++-- .../groovy/org/openbakery/xcode/Xcode.groovy | 55 +++++++++++++------ .../org/openbakery/AbstractXcodeTask.groovy | 6 +- .../carthage/AbstractCarthageTaskBase.groovy | 5 ++ .../carthage/CarthageBootStrapTask.groovy | 2 +- .../output/ConsoleOutputAppender.java | 1 - 6 files changed, 71 insertions(+), 26 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index d845bacc..00d8015b 100644 --- a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy +++ b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy @@ -76,7 +76,8 @@ class CommandRunner { commandOutputBuffer = new CircularFifoBuffer(20); } - def commandsAsStrings = commandList.collect { it.toString() } // GStrings don't play well with ProcessBuilder + def commandsAsStrings = commandList.collect { it.toString() } + // GStrings don't play well with ProcessBuilder def processBuilder = new ProcessBuilder(commandsAsStrings) processBuilder.redirectErrorStream(true) processBuilder.directory(new File(directory)) @@ -172,20 +173,35 @@ class CommandRunner { } String runWithResult(String... commandList) { - return runWithResult(Arrays.asList(commandList)); + return runWithResult(Arrays.asList(commandList)) + } + + String runWithResult(Map environmentValues, + String... commandList) { + return runWithResult(defaultBaseDirectory, + commandList.toList(), + environmentValues, + null) } String runWithResult(List commandList) { return runWithResult(defaultBaseDirectory, commandList) } - String runWithResult(String directory, List commandList) { - return runWithResult(directory, commandList, null, null) + String runWithResult(String directory, + List commandList) { + return runWithResult(directory, + commandList, + null, + null) } - String runWithResult(String directory, List commandList, Map environment, OutputAppender outputAppender) { + String runWithResult(String directory, + List commandList, + Map environment, + OutputAppender outputAppender) { commandOutputBuffer = new ArrayList<>(); - run(directory, commandList, environment, outputAppender); + run(directory, commandList, environment, outputAppender) String result = commandOutputBuffer.join("\n") commandOutputBuffer = null; return result diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index 8bc50f27..ea0842a3 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -13,6 +13,9 @@ class Xcode { String xcodePath Version version = null + public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" + public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" + public static final String XCODE_CONTENT_XCODEBUILD = "Contents/Developer/usr/bin/xcodebuild" public Xcode(CommandRunner commandRunner) { this(commandRunner, null) @@ -26,30 +29,47 @@ class Xcode { } } + /** + * Provide the environments values to provide to the command line runner to select + * a Xcode version without using `xcode-select -s` who requires `sudo`. + * + * @param version : The required Xcode version + * @return A map of environment variables to pass to the command runner + */ + Map getXcodeSelectEnvValue(String version) { + setVersionFromString(version) + + HashMap result = new HashMap() + result.put(ENV_DEVELOPER_DIR, new File(xcodePath, XCODE_CONTENT_DEVELOPER).absolutePath) + return result + } + void setVersionFromString(String version) { - Version versionToCompare = new Version(version) + Optional requiredVersion = Optional.ofNullable(version) + .map { new Version(it) } + String installedXcodes = commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + Iterator files = installedXcodes.split("\n").iterator() + .collect { new File(it, XCODE_CONTENT_XCODEBUILD) } + .findAll { it.exists() } + .iterator() - for (String xcode : installedXcodes.split("\n")) { - File xcodeBuildFile = new File(xcode, "Contents/Developer/usr/bin/xcodebuild"); - if (xcodeBuildFile.exists()) { - Version xcodeVersion = getXcodeVersion(xcodeBuildFile.absolutePath) - if (xcodeVersion.suffix != null && versionToCompare.suffix != null) { - if (xcodeVersion.suffix.equalsIgnoreCase(versionToCompare.suffix)) { - xcodePath = xcode - this.version = xcodeVersion - return - } - } else if (xcodeVersion.toString().startsWith(versionToCompare.toString())) { - xcodePath = xcode + for (File xcodeBuildFile : files) { + Version xcodeVersion = getXcodeVersion(xcodeBuildFile.absolutePath) + if (xcodeVersion.suffix != null && requiredVersion.get().suffix != null) { + if (xcodeVersion.suffix.equalsIgnoreCase(requiredVersion.get().suffix)) { + xcodePath = new File(xcodeBuildFile.absolutePath - XCODE_CONTENT_XCODEBUILD) this.version = xcodeVersion return } + } else if (xcodeVersion.toString().startsWith(requiredVersion.get().toString())) { + xcodePath = new File(xcodeBuildFile.absolutePath - XCODE_CONTENT_XCODEBUILD) + this.version = xcodeVersion + return } } throw new IllegalStateException("No Xcode found with build number " + version); - } Version getXcodeVersion(String xcodebuildCommand) { @@ -103,8 +123,9 @@ class Xcode { @Override public String toString() { return "Xcode{" + - "xcodePath='" + xcodePath + '\'' + - ", version=" + version + - '}'; + "xcodePath='" + xcodePath + '\'' + + ", version=" + version + + '}'; } + } diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy index 33394036..d2b026f8 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy @@ -202,11 +202,15 @@ abstract class AbstractXcodeTask extends DefaultTask { Xcode getXcode() { if (xcode == null) { - xcode = new Xcode(commandRunner, project.xcodebuild.xcodeVersion) + xcode = new Xcode(commandRunner, getProjectXcodeVersion()) } return xcode } + String getProjectXcodeVersion() { + return project.xcodebuild.xcodeVersion + } + DestinationResolver getDestinationResolver() { if (destinationResolver == null) { destinationResolver = new DestinationResolver(getSimulatorControl()) diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy index 5e36d2ae..21c122f3 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -23,6 +23,11 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { super() } + @Input + String getRequiredXcodeVersion() { + return getProjectXcodeVersion() + } + @InputFile @Optional @PathSensitive(PathSensitivity.RELATIVE) diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index e8289369..fc69153c 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -15,7 +15,6 @@ class CarthageBootStrapTask extends AbstractCarthageTaskBase { void update() { if (hasCartFile()) { logger.info('Boostrap Carthage for platform ' + carthagePlatformName) - def output = services.get(StyledTextOutputFactory) .create(CarthageBootStrapTask) @@ -26,6 +25,7 @@ class CarthageBootStrapTask extends AbstractCarthageTaskBase { ARG_PLATFORM, carthagePlatformName, ARG_CACHE_BUILDS], + xcode.getXcodeSelectEnvValue(project.xcodebuild.xcodeVersion), new ConsoleOutputAppender(output)) } } diff --git a/plugin/src/main/groovy/org/openbakery/output/ConsoleOutputAppender.java b/plugin/src/main/groovy/org/openbakery/output/ConsoleOutputAppender.java index fa05b9a8..bcd1c5ff 100644 --- a/plugin/src/main/groovy/org/openbakery/output/ConsoleOutputAppender.java +++ b/plugin/src/main/groovy/org/openbakery/output/ConsoleOutputAppender.java @@ -15,7 +15,6 @@ public ConsoleOutputAppender(StyledTextOutput output) { @Override public void append(String line) { output.withStyle(StyledTextOutput.Style.Info).println(line); - } } From 5801d052fe60c436f6319e9bf9be34bc148c3673 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 09:20:07 +0100 Subject: [PATCH 026/121] Adjusting the Xcode class to make it @CompileStatic and tweaks it's unit tests --- .../org/openbakery/xcode/Version.groovy | 2 - .../groovy/org/openbakery/xcode/Xcode.groovy | 112 +++-- .../xcode/XcodeSpecification.groovy | 433 +++++++++--------- 3 files changed, 296 insertions(+), 251 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy index de92bc57..c373cb42 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy @@ -30,8 +30,6 @@ class Version implements Comparable { } catch (InputMismatchException ex) { suffix = versionScanner.next() } - - } @Override diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index ea0842a3..d0b4767f 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -1,27 +1,34 @@ package org.openbakery.xcode +import groovy.transform.CompileStatic import org.openbakery.CommandRunner import org.slf4j.Logger import org.slf4j.LoggerFactory -class Xcode { - private static Logger logger = LoggerFactory.getLogger(Xcode.class) - +import java.util.regex.Matcher +import java.util.regex.Pattern - CommandRunner commandRunner +@CompileStatic +class Xcode { + private Version version = null + private String xcodePath - String xcodePath - Version version = null + private final CommandRunner commandRunner public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" - public static final String XCODE_CONTENT_XCODEBUILD = "Contents/Developer/usr/bin/xcodebuild" + public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" + public static final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" + + private final Logger logger = LoggerFactory.getLogger(Xcode.class) + + private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ - public Xcode(CommandRunner commandRunner) { + Xcode(CommandRunner commandRunner) { this(commandRunner, null) } - public Xcode(CommandRunner commandRunner, String version) { + Xcode(CommandRunner commandRunner, String version) { logger.debug("create xcode with version {}", version) this.commandRunner = commandRunner if (version != null) { @@ -44,42 +51,58 @@ class Xcode { return result } - void setVersionFromString(String version) { - Optional requiredVersion = Optional.ofNullable(version) - .map { new Version(it) } + void setVersionFromString(String version) throws IllegalArgumentException { + if (version == null) { + throw new IllegalArgumentException() + } - String installedXcodes = commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + final Version requiredVersion = new Version(version) - Iterator files = installedXcodes.split("\n").iterator() - .collect { new File(it, XCODE_CONTENT_XCODEBUILD) } - .findAll { it.exists() } + Optional result = Optional.ofNullable(resolveInstalledXcodeVersionsList() + .split("\n") .iterator() + .collect { new File(it as File, XCODE_CONTENT_XCODE_BUILD) } + .findAll { it.exists() } + .find { + Version candidate = getXcodeVersion(it.absolutePath) + + boolean versionStartWith = candidate.toString() + .startsWith(requiredVersion.toString()) - for (File xcodeBuildFile : files) { - Version xcodeVersion = getXcodeVersion(xcodeBuildFile.absolutePath) - if (xcodeVersion.suffix != null && requiredVersion.get().suffix != null) { - if (xcodeVersion.suffix.equalsIgnoreCase(requiredVersion.get().suffix)) { - xcodePath = new File(xcodeBuildFile.absolutePath - XCODE_CONTENT_XCODEBUILD) - this.version = xcodeVersion - return - } - } else if (xcodeVersion.toString().startsWith(requiredVersion.get().toString())) { - xcodePath = new File(xcodeBuildFile.absolutePath - XCODE_CONTENT_XCODEBUILD) - this.version = xcodeVersion - return - } + boolean versionHasSuffix = (candidate.suffix != null + && requiredVersion.suffix != null + && candidate.suffix.equalsIgnoreCase(requiredVersion.suffix)) + + return versionHasSuffix || versionStartWith + }) + + if (result.isPresent()) { + selectXcode(result.get()) + } else { + throw new IllegalStateException("No Xcode found with build number " + version) } - throw new IllegalStateException("No Xcode found with build number " + version); } - Version getXcodeVersion(String xcodebuildCommand) { - String xcodeVersion = commandRunner.runWithResult(xcodebuildCommand, "-version"); + void selectXcode(File file) { + String absolutePath = file.absolutePath + Version xcodeVersion = getXcodeVersion(absolutePath) + xcodePath = new File(absolutePath - XCODE_CONTENT_XCODE_BUILD) + this.version = xcodeVersion + } + + String resolveInstalledXcodeVersionsList() { + return commandRunner.runWithResult("mdfind", + "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + } + + Version getXcodeVersion(String xcodeBuildCommand) { + String xcodeVersion = commandRunner.runWithResult(xcodeBuildCommand, + "-version") - def VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ - def matcher = VERSION_PATTERN.matcher(xcodeVersion) + Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) if (matcher.matches()) { - Version version = new Version(matcher[0][1]) - version.suffix = matcher[0][2] + Version version = new Version(matcher.group(1)) + version.suffix = matcher.group(2) return version } return null @@ -95,37 +118,36 @@ class Xcode { String getPath() { if (xcodePath == null) { String result = commandRunner.runWithResult("xcode-select", "-p") - xcodePath = result - "/Contents/Developer" + xcodePath = result - "/$XCODE_CONTENT_DEVELOPER" } return xcodePath } - String getXcodebuild() { if (xcodePath != null) { - return xcodePath + "/Contents/Developer/usr/bin/xcodebuild" + return new File(xcodePath, XCODE_CONTENT_XCODE_BUILD).absolutePath } return "xcodebuild" } String getAltool() { - return getPath() + "/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" + return getPath() + "/Contents/Applications/Application Loader" + + ".app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" } String getXcrun() { - return getPath() + "/Contents/Developer/usr/bin/xcrun" + return getPath() + XCODE_CONTENT_XC_RUN } String getSimctl() { - return getPath() + "/Contents/Developer/usr/bin/simctl" + return getPath() + "/$XCODE_CONTENT_DEVELOPER/usr/bin/simctl" } @Override - public String toString() { + String toString() { return "Xcode{" + "xcodePath='" + xcodePath + '\'' + ", version=" + version + - '}'; + '}' } - } diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy index 7ab51de2..08123b4d 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy @@ -2,224 +2,249 @@ package org.openbakery.xcode import org.apache.commons.io.FileUtils import org.openbakery.CommandRunner -import org.openbakery.xcode.Version -import org.openbakery.xcode.Xcode import spock.lang.Specification +import spock.lang.Unroll class XcodeSpecification extends Specification { - Xcode xcode + Xcode xcode - CommandRunner commandRunner = Mock(CommandRunner) + CommandRunner commandRunner = Mock(CommandRunner) - File xcode7_1_1 - File xcode6_1 - File xcode6_0 - File xcode5_1 + static File xcode7_1_1 = new File(File.createTempDir(), "Xcode7.1.1.app") + static File xcode6_1 = new File(File.createTempDir(), "Xcode6-1.app") + static File xcode6_0 = new File(File.createTempDir(), "Xcode6.app") + static File xcode5_1 = new File(File.createTempDir(), "Xcode5.app") - def setup() { + def setup() { + xcode = Spy(Xcode, constructorArgs: [commandRunner]) + + new File(xcode7_1_1, "Contents/Developer/usr/bin").mkdirs() + new File(xcode6_1, "Contents/Developer/usr/bin").mkdirs() + new File(xcode6_0, "Contents/Developer/usr/bin").mkdirs() + new File(xcode5_1, "Contents/Developer/usr/bin").mkdirs() - xcode = new Xcode(commandRunner) + new File(xcode7_1_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() + new File(xcode6_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() + new File(xcode6_0, "Contents/Developer/usr/bin/xcodebuild").createNewFile() + new File(xcode5_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() + } + + def cleanup() { + FileUtils.deleteDirectory(xcode7_1_1) + FileUtils.deleteDirectory(xcode6_1) + FileUtils.deleteDirectory(xcode6_0) + FileUtils.deleteDirectory(xcode5_1) + } - xcode7_1_1 = new File(System.getProperty("java.io.tmpdir"), "Xcode7.1.1.app") - xcode6_1 = new File(System.getProperty("java.io.tmpdir"), "Xcode6-1.app") - xcode6_0 = new File(System.getProperty("java.io.tmpdir"), "Xcode6.app") - xcode5_1 = new File(System.getProperty("java.io.tmpdir"), "Xcode5.app") - new File(xcode7_1_1, "Contents/Developer/usr/bin").mkdirs() - new File(xcode6_1, "Contents/Developer/usr/bin").mkdirs() - new File(xcode6_0, "Contents/Developer/usr/bin").mkdirs() - new File(xcode5_1, "Contents/Developer/usr/bin").mkdirs() + def "test default xcode path"() { + given: + useDefaultXcode() - new File(xcode7_1_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() - new File(xcode6_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() - new File(xcode6_0, "Contents/Developer/usr/bin/xcodebuild").createNewFile() - new File(xcode5_1, "Contents/Developer/usr/bin/xcodebuild").createNewFile() + expect: + xcode.getPath().equals("/Applications/Xcode.app") + } + def useXcode(String version) { + mockInstalledXcodeVersions() - } + xcode = new Xcode(commandRunner, version) + } - def cleanup() { - FileUtils.deleteDirectory(xcode7_1_1) - FileUtils.deleteDirectory(xcode6_1) - FileUtils.deleteDirectory(xcode6_0) - FileUtils.deleteDirectory(xcode5_1) - } + def mockInstalledXcodeVersions() { + commandRunner.runWithResult(xcode5_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 5.1.1\nBuild version 5B1008") + commandRunner.runWithResult(xcode6_0.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 6.0\nBuild version 6A000") + commandRunner.runWithResult(xcode6_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 6.4\nBuild version 6E35b") + commandRunner.runWithResult(xcode7_1_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 7.1.1\nBuild version 7B1005") + commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") >> xcode5_1.absolutePath + "\n" + xcode6_0.absolutePath + "\n" + xcode6_1.absolutePath + "\n" + xcode7_1_1.absolutePath + } - def "test default xcode path"() { - given: - useDefaultXcode() - - expect: - xcode.getPath().equals("/Applications/Xcode.app") - - } - - - def useXcode(String version) { - commandRunner.runWithResult(xcode5_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 5.1.1\nBuild version 5B1008") - commandRunner.runWithResult(xcode6_0.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 6.0\nBuild version 6A000") - commandRunner.runWithResult(xcode6_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 6.4\nBuild version 6E35b") - commandRunner.runWithResult(xcode7_1_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> ("Xcode 7.1.1\nBuild version 7B1005") - commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") >> xcode5_1.absolutePath + "\n" + xcode6_0.absolutePath + "\n" + xcode6_1.absolutePath + "\n" + xcode7_1_1.absolutePath - - xcode = new Xcode(commandRunner, version) - } - - - def useDefaultXcode() { - commandRunner.runWithResult("xcode-select", "-p") >> ("/Applications/Xcode.app/Contents/Developer") - } - - def "xcodebuild of Xcode 5 is used"() { - given: - useXcode("5B1008") - - expect: - xcode.getXcodebuild().endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") - } - - def "xcodebuild of Xcode 5 simple version number"() { - given: - useXcode("5.1") - - expect: - xcode.getXcodebuild().endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") - } - - - def "xcode Version Simple 1"() { - - given: - useXcode("5.1.1") - - expect: - xcode.getXcodebuild().endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") - } - - def "xcodeVersion Simple not found"() { - when: - useXcode("5.1.2") - - then: - thrown(IllegalStateException) - } - - - def "xcodeVersion select last"() { - commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") >> xcode6_1.absolutePath + "\n" + xcode6_0.absolutePath + "\n" + xcode5_1.absolutePath - commandRunner.runWithResult(xcode6_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 6.0\nBuild version 6A000" - commandRunner.runWithResult(xcode6_0.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 6.0\nBuild version 6A000" - commandRunner.runWithResult(xcode5_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 5.1.1\nBuild version 5B1008" - - when: - xcode = new Xcode(commandRunner, '5B1008') - - then: - xcode.getXcodebuild().endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") - } - - - def "xcodeVersion select not found"() { - useXcode("5B1008") - - when: - xcode = new Xcode(commandRunner, '5B1009') - - then: - thrown(IllegalStateException) - } - - def "version is not null"() { - given: - commandRunner.runWithResult("xcodebuild", "-version") >> ("Xcode 7.3.1\nBuild version 7D1014") - - expect: - xcode.getVersion() != null - xcode.getVersion().major == 7 - xcode.getVersion().minor == 3 - xcode.getVersion().maintenance == 1 - } - - - def "altool default path"() { - given: - useDefaultXcode() - - expect: - xcode.getAltool() == '/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool' - } - - def "altool with xcode 7.1.1"() { - given: - useXcode("7.1") - - expect: - xcode.getAltool().contains('Xcode7.1.1.app') - xcode.getAltool().endsWith('Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool') - } - - def "xcrun default path"() { - given: - useDefaultXcode() - - expect: - xcode.getXcrun() == '/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun' - } - - - def "xcrun with xcode 7.1.1"() { - given: - useXcode("7.1") - - expect: - xcode.getXcrun().endsWith('Xcode7.1.1.app/Contents/Developer/usr/bin/xcrun') - } - - - - def "set xcode version"() { - useXcode("7.1") - - - expect: - xcode.version instanceof Version - xcode.version.major == 7 - xcode.version.minor == 1 - xcode.version.maintenance == 1 - } - - def "set xcode version with xcode 6"() { - useXcode("6.4") - - expect: - xcode.version instanceof Version - xcode.version.major == 6 - xcode.version.minor == 4 - xcode.version.maintenance == -1 - } - - def "get xcode version"() { - given: - commandRunner.runWithResult("xcodebuild", "-version") >> ("Xcode 6.4\nBuild version 6E35b") - - when: - Version version = xcode.version - - then: - version instanceof Version - version.major == 6 - version.minor == 4 - version.maintenance == -1 - } - - - def "simctl default path"() { - given: - useDefaultXcode() - - expect: - xcode.getSimctl() == '/Applications/Xcode.app/Contents/Developer/usr/bin/simctl' - } + def useDefaultXcode() { + commandRunner.runWithResult("xcode-select", "-p") >> ("/Applications/Xcode.app/Contents/Developer") + } + @Unroll + def "xcodebuild of Xcode 5 is used"() { + given: + useXcode("5B1008") + expect: + xcode.getXcodebuild() + .endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") + + where: + version | _ + "5B1008" | _ + "5.1" | _ + "5.1.1" | _ + } + + def "xcodeVersion Simple not found"() { + when: + useXcode("5.1.2") + + then: + thrown(IllegalStateException) + } + + def "xcodeVersion select last"() { + commandRunner.runWithResult("mdfind", "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") >> xcode6_1.absolutePath + "\n" + xcode6_0.absolutePath + "\n" + xcode5_1.absolutePath + commandRunner.runWithResult(xcode6_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 6.0\nBuild version 6A000" + commandRunner.runWithResult(xcode6_0.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 6.0\nBuild version 6A000" + commandRunner.runWithResult(xcode5_1.absolutePath + "/Contents/Developer/usr/bin/xcodebuild", "-version") >> "Xcode 5.1.1\nBuild version 5B1008" + + when: + xcode = new Xcode(commandRunner, '5B1008') + + then: + xcode.getXcodebuild().endsWith("Xcode5.app/Contents/Developer/usr/bin/xcodebuild") + } + + + def "xcodeVersion select not found"() { + useXcode("5B1008") + + when: + xcode = new Xcode(commandRunner, '5B1009') + + then: + thrown(IllegalStateException) + } + + def "version is not null"() { + given: + commandRunner.runWithResult("xcodebuild", "-version") >> ("Xcode 7.3.1\nBuild version 7D1014") + + expect: + xcode.getVersion() != null + xcode.getVersion().major == 7 + xcode.getVersion().minor == 3 + xcode.getVersion().maintenance == 1 + } + + + def "altool default path"() { + given: + useDefaultXcode() + + expect: + xcode.getAltool() == '/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool' + } + + def "altool with xcode 7.1.1"() { + given: + useXcode("7.1") + + expect: + xcode.getAltool().contains('Xcode7.1.1.app') + xcode.getAltool().endsWith('Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool') + } + + def "xcrun default path"() { + given: + useDefaultXcode() + + expect: + xcode.getXcrun() == '/Applications/Xcode.app/Contents/Developer/usr/bin/xcrun' + } + + + def "xcrun with xcode 7.1.1"() { + given: + useXcode("7.1") + + expect: + xcode.getXcrun().endsWith('Xcode7.1.1.app/Contents/Developer/usr/bin/xcrun') + } + + def "set xcode version"() { + setup: + useXcode(version) + + expect: + xcode.version instanceof Version + xcode.version.major == major + xcode.version.minor == minor + xcode.version.maintenance == maintenance + + where: + version | major | minor | maintenance + "5.1.1" | 5 | 1 | 1 + "6.0" | 6 | 0 | -1 + "6.4" | 6 | 4 | -1 + "7.1.1" | 7 | 1 | 1 + } + + def "get xcode version"() { + given: + commandRunner.runWithResult("xcodebuild", "-version") >> ("Xcode 6.4\nBuild version 6E35b") + + when: + Version version = xcode.version + + then: + version instanceof Version + version.major == 6 + version.minor == 4 + version.maintenance == -1 + } + + + def "simctl default path"() { + given: + useDefaultXcode() + + expect: + xcode.getSimctl() == '/Applications/Xcode.app/Contents/Developer/usr/bin/simctl' + } + + def "Should be able to resolve a Xcode version by string without exception when valid"() { + when: + mockInstalledXcodeVersions() + xcode.setVersionFromString(version) + + then: + 1 * xcode.selectXcode(new File(file, Xcode.XCODE_CONTENT_XCODE_BUILD)) + xcode.version.toString() == (version + "." + buildVersion) + noExceptionThrown() + + where: + version | buildVersion | file + "5.1.1" | "5B1008" | xcode5_1 + "6.0" | "6A000" | xcode6_0 + "7.1.1" | "7B1005" | xcode7_1_1 + } + + def "Should raise an exception when resolving a invalid Xcode instance by version string"() { + when: + mockInstalledXcodeVersions() + xcode.setVersionFromString(version) + + then: + thrown(exception) + 0 * xcode.selectXcode(_) + + where: + version | exception + "5.1.3" | IllegalStateException + "10.0" | IllegalStateException + "7.1.3" | IllegalStateException + null | IllegalArgumentException + } + + def "Should return a map of environment values containing the developer dir key for valid xcode version"() { + when: + mockInstalledXcodeVersions() + Map envValues = xcode.getXcodeSelectEnvValue(version) + + then: + noExceptionThrown() + envValues.get(Xcode.ENV_DEVELOPER_DIR) == new File(file, Xcode.XCODE_CONTENT_DEVELOPER).absolutePath + + where: + version | file + "5.1.1" | xcode5_1 + "6.0" | xcode6_0 + "7.1.1" | xcode7_1_1 + } } From 054cd3b7a53105625d616f18d73500284208e744 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 09:38:49 +0100 Subject: [PATCH 027/121] Make the task @CompileStatic --- .../org/openbakery/carthage/CarthageBootStrapTask.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index fc69153c..c1b98bf1 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -1,9 +1,11 @@ package org.openbakery.carthage +import groovy.transform.CompileStatic import org.gradle.api.tasks.TaskAction import org.gradle.internal.logging.text.StyledTextOutputFactory import org.openbakery.output.ConsoleOutputAppender +@CompileStatic class CarthageBootStrapTask extends AbstractCarthageTaskBase { CarthageBootStrapTask() { @@ -25,7 +27,7 @@ class CarthageBootStrapTask extends AbstractCarthageTaskBase { ARG_PLATFORM, carthagePlatformName, ARG_CACHE_BUILDS], - xcode.getXcodeSelectEnvValue(project.xcodebuild.xcodeVersion), + xcode.getXcodeSelectEnvValue(getRequiredXcodeVersion()), new ConsoleOutputAppender(output)) } } From c17e0eddef484a32664dc1721ae6de6da5056876 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 14:40:35 +0100 Subject: [PATCH 028/121] Adjustements in the unit tests --- .../org/openbakery/CommandRunner.groovy | 3 +- .../groovy/org/openbakery/xcode/Xcode.groovy | 9 ++-- .../XcodeBuildPluginExtension.groovy | 4 +- .../carthage/AbstractCarthageTaskBase.groovy | 1 + .../carthage/CarthageBootStrapTask.groovy | 17 ++++---- .../carthage/CarthageBootStrapTaskTest.groovy | 43 ++++++++++++++++--- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index 00d8015b..f49fc702 100644 --- a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy +++ b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy @@ -76,8 +76,7 @@ class CommandRunner { commandOutputBuffer = new CircularFifoBuffer(20); } - def commandsAsStrings = commandList.collect { it.toString() } - // GStrings don't play well with ProcessBuilder + def commandsAsStrings = commandList.collect { it.toString() } // GStrings don't play well with ProcessBuilder def processBuilder = new ProcessBuilder(commandsAsStrings) processBuilder.redirectErrorStream(true) processBuilder.directory(new File(directory)) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index d0b4767f..9bb6fa5e 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -18,7 +18,8 @@ class Xcode { public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" - public static final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" + public static + final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" private final Logger logger = LoggerFactory.getLogger(Xcode.class) @@ -45,9 +46,11 @@ class Xcode { */ Map getXcodeSelectEnvValue(String version) { setVersionFromString(version) - + File file = new File(xcodePath, XCODE_CONTENT_DEVELOPER) HashMap result = new HashMap() - result.put(ENV_DEVELOPER_DIR, new File(xcodePath, XCODE_CONTENT_DEVELOPER).absolutePath) + if (file.exists()) { + result.put(ENV_DEVELOPER_DIR, file.absolutePath) + } return result } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 921e333e..df5e5a4b 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -469,7 +469,7 @@ class XcodeBuildPluginExtension { xcode = new Xcode(commandRunner, xcodeVersion) } logger.debug("using xcode {}", xcode) - return xcode + return xcode } @@ -500,4 +500,4 @@ class XcodeBuildPluginExtension { return result } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy index 21c122f3..abbb6664 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -24,6 +24,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { } @Input + @Optional String getRequiredXcodeVersion() { return getProjectXcodeVersion() } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index c1b98bf1..7c6e8c43 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -20,14 +20,15 @@ class CarthageBootStrapTask extends AbstractCarthageTaskBase { def output = services.get(StyledTextOutputFactory) .create(CarthageBootStrapTask) - commandRunner.run( - project.projectDir.absolutePath, - [getCarthageCommand(), - ACTION_BOOTSTRAP, - ARG_PLATFORM, - carthagePlatformName, - ARG_CACHE_BUILDS], - xcode.getXcodeSelectEnvValue(getRequiredXcodeVersion()), + List args = [getCarthageCommand(), + ACTION_BOOTSTRAP, + ARG_PLATFORM, + carthagePlatformName, + ARG_CACHE_BUILDS] + + commandRunner.run(project.projectDir.absolutePath, + args, + getRequiredXcodeVersion() != null ? xcode.getXcodeSelectEnvValue(getRequiredXcodeVersion()) : null, new ConsoleOutputAppender(output)) } } diff --git a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy index 47cd2036..8f45eeb5 100644 --- a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy +++ b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy @@ -7,6 +7,7 @@ import org.junit.Rule import org.junit.rules.ExpectedException import org.openbakery.CommandRunner import org.openbakery.output.ConsoleOutputAppender +import org.openbakery.xcode.Xcode import spock.lang.Specification import spock.lang.Unroll @@ -17,6 +18,7 @@ class CarthageBootStrapTaskTest extends Specification { CarthageBootStrapTask subject CommandRunner commandRunner = Mock(CommandRunner) + Xcode mockXcode = Mock(Xcode) File projectDir File cartFile Project project @@ -64,8 +66,9 @@ class CarthageBootStrapTaskTest extends Specification { ARG_PLATFORM, carthagePlatform, ARG_CACHE_BUILDS] + , _ , _) >> { - args -> args[2] instanceof ConsoleOutputAppender + args -> args[3] instanceof ConsoleOutputAppender } where: @@ -86,12 +89,11 @@ class CarthageBootStrapTaskTest extends Specification { subject.update() then: - 0 * commandRunner.run(_, [CARTHAGE_USR_BIN_PATH, - ACTION_UPDATE, - ARG_PLATFORM, - carthagePlatform, - ARG_CACHE_BUILDS], _) >> { - args -> args[2] instanceof ConsoleOutputAppender + 0 * commandRunner.run(_, + getCommandRunnerArgsForPlatform(carthagePlatform), + _, + _) >> { + args -> args[3] instanceof ConsoleOutputAppender } where: @@ -104,6 +106,7 @@ class CarthageBootStrapTaskTest extends Specification { def "The subject output directory should be platform dependant"() { when: + subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() project.xcodebuild.type = platform then: @@ -118,4 +121,30 @@ class CarthageBootStrapTaskTest extends Specification { watchOS | CARTHAGE_PLATFORM_WATCHOS iOS | CARTHAGE_PLATFORM_IOS } + + def "The xcode selection should be applied if a xcode version is defined"() { + when: + subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() + project.xcodebuild.type = iOS + project.xcodebuild.version = version + + subject.xcode = mockXcode + subject.xcode.setVersionFromString(_) >> _ + subject.update() + + then: + 1 * mockXcode.getXcodeSelectEnvValue(version) + + where: + version | _ + "7.1.1" | _ + } + + private List getCommandRunnerArgsForPlatform(String carthagePlatform) { + return [CARTHAGE_USR_BIN_PATH, + ACTION_UPDATE, + ARG_PLATFORM, + carthagePlatform, + ARG_CACHE_BUILDS] + } } From 7ff4e02dad54d1b514c447ee99d4c72eddb46466 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 14:49:17 +0100 Subject: [PATCH 029/121] Fix unit tests --- .../groovy/org/openbakery/xcode/Xcode.groovy | 293 +++++++++--------- 1 file changed, 150 insertions(+), 143 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index 9bb6fa5e..8b539f9e 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -1,6 +1,7 @@ package org.openbakery.xcode import groovy.transform.CompileStatic +import org.gradle.internal.impldep.com.google.common.annotations.VisibleForTesting import org.openbakery.CommandRunner import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -10,147 +11,153 @@ import java.util.regex.Pattern @CompileStatic class Xcode { - private Version version = null - private String xcodePath - - private final CommandRunner commandRunner - - public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" - public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" - public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" - public static - final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" - - private final Logger logger = LoggerFactory.getLogger(Xcode.class) - - private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ - - Xcode(CommandRunner commandRunner) { - this(commandRunner, null) - } - - Xcode(CommandRunner commandRunner, String version) { - logger.debug("create xcode with version {}", version) - this.commandRunner = commandRunner - if (version != null) { - setVersionFromString(version) - } - } - - /** - * Provide the environments values to provide to the command line runner to select - * a Xcode version without using `xcode-select -s` who requires `sudo`. - * - * @param version : The required Xcode version - * @return A map of environment variables to pass to the command runner - */ - Map getXcodeSelectEnvValue(String version) { - setVersionFromString(version) - File file = new File(xcodePath, XCODE_CONTENT_DEVELOPER) - HashMap result = new HashMap() - if (file.exists()) { - result.put(ENV_DEVELOPER_DIR, file.absolutePath) - } - return result - } - - void setVersionFromString(String version) throws IllegalArgumentException { - if (version == null) { - throw new IllegalArgumentException() - } - - final Version requiredVersion = new Version(version) - - Optional result = Optional.ofNullable(resolveInstalledXcodeVersionsList() - .split("\n") - .iterator() - .collect { new File(it as File, XCODE_CONTENT_XCODE_BUILD) } - .findAll { it.exists() } - .find { - Version candidate = getXcodeVersion(it.absolutePath) - - boolean versionStartWith = candidate.toString() - .startsWith(requiredVersion.toString()) - - boolean versionHasSuffix = (candidate.suffix != null - && requiredVersion.suffix != null - && candidate.suffix.equalsIgnoreCase(requiredVersion.suffix)) - - return versionHasSuffix || versionStartWith - }) - - if (result.isPresent()) { - selectXcode(result.get()) - } else { - throw new IllegalStateException("No Xcode found with build number " + version) - } - } - - void selectXcode(File file) { - String absolutePath = file.absolutePath - Version xcodeVersion = getXcodeVersion(absolutePath) - xcodePath = new File(absolutePath - XCODE_CONTENT_XCODE_BUILD) - this.version = xcodeVersion - } - - String resolveInstalledXcodeVersionsList() { - return commandRunner.runWithResult("mdfind", - "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") - } - - Version getXcodeVersion(String xcodeBuildCommand) { - String xcodeVersion = commandRunner.runWithResult(xcodeBuildCommand, - "-version") - - Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) - if (matcher.matches()) { - Version version = new Version(matcher.group(1)) - version.suffix = matcher.group(2) - return version - } - return null - } - - Version getVersion() { - if (this.version == null) { - this.version = getXcodeVersion(getXcodebuild()) - } - return this.version - } - - String getPath() { - if (xcodePath == null) { - String result = commandRunner.runWithResult("xcode-select", "-p") - xcodePath = result - "/$XCODE_CONTENT_DEVELOPER" - } - return xcodePath - } - - String getXcodebuild() { - if (xcodePath != null) { - return new File(xcodePath, XCODE_CONTENT_XCODE_BUILD).absolutePath - } - return "xcodebuild" - } - - String getAltool() { - return getPath() + "/Contents/Applications/Application Loader" + - ".app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" - } - - String getXcrun() { - return getPath() + XCODE_CONTENT_XC_RUN - } - - String getSimctl() { - return getPath() + "/$XCODE_CONTENT_DEVELOPER/usr/bin/simctl" - } - - @Override - String toString() { - return "Xcode{" + - "xcodePath='" + xcodePath + '\'' + - ", version=" + version + - '}' - } + private Version version = null + private String xcodePath + + @VisibleForTesting + private CommandRunner commandRunner + + public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" + public static final String XCODE_ACTION_XC_SELECT = "xcode-select" + public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" + public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" + public static final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" + + private final Logger logger = LoggerFactory.getLogger(Xcode.class) + + private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ + + Xcode(CommandRunner commandRunner) { + this(commandRunner, null) + } + + Xcode(CommandRunner commandRunner, String version) { + logger.debug("create xcode with version {}", version) + this.commandRunner = commandRunner + if (version != null) { + setVersionFromString(version) + } + } + + CommandRunner getCommandRunner() { + return commandRunner + } + + /** + * Provide the environments values to provide to the command line runner to select + * a Xcode version without using `xcode-select -s` who requires `sudo`. + * + * @param version : The required Xcode version + * @return A map of environment variables to pass to the command runner + */ + Map getXcodeSelectEnvValue(String version) { + setVersionFromString(version) + File file = new File(xcodePath, XCODE_CONTENT_DEVELOPER) + HashMap result = new HashMap() + if (file.exists()) { + result.put(ENV_DEVELOPER_DIR, file.absolutePath) + } + return result + } + + void setVersionFromString(String version) throws IllegalArgumentException { + if (version == null) { + throw new IllegalArgumentException() + } + + final Version requiredVersion = new Version(version) + + Optional result = Optional.ofNullable(resolveInstalledXcodeVersionsList() + .split("\n") + .iterator() + .collect { new File(it as File, XCODE_CONTENT_XCODE_BUILD) } + .findAll { it.exists() } + .find { + Version candidate = getXcodeVersion(it.absolutePath) + + boolean versionStartWith = candidate.toString() + .startsWith(requiredVersion.toString()) + + boolean versionHasSuffix = (candidate.suffix != null + && requiredVersion.suffix != null + && candidate.suffix.equalsIgnoreCase(requiredVersion.suffix)) + + return versionHasSuffix || versionStartWith + }) + + if (result.isPresent()) { + selectXcode(result.get()) + } else { + throw new IllegalStateException("No Xcode found with build number " + version) + } + } + + void selectXcode(File file) { + String absolutePath = file.absolutePath + Version xcodeVersion = getXcodeVersion(absolutePath) + xcodePath = new File(absolutePath - XCODE_CONTENT_XCODE_BUILD) + this.version = xcodeVersion + } + + String resolveInstalledXcodeVersionsList() { + return commandRunner.runWithResult("mdfind", + "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + } + + Version getXcodeVersion(String xcodeBuildCommand) { + String xcodeVersion = commandRunner.runWithResult(xcodeBuildCommand, + "-version") + + Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) + if (matcher.matches()) { + Version version = new Version(matcher.group(1)) + version.suffix = matcher.group(2) + return version + } + return null + } + + Version getVersion() { + if (this.version == null) { + this.version = getXcodeVersion(getXcodebuild()) + } + return this.version + } + + String getPath() { + if (xcodePath == null) { + String result = commandRunner.runWithResult(XCODE_ACTION_XC_SELECT + , "-p") + xcodePath = result - "/$XCODE_CONTENT_DEVELOPER" + } + return xcodePath + } + + String getXcodebuild() { + if (xcodePath != null) { + return new File(xcodePath, XCODE_CONTENT_XCODE_BUILD).absolutePath + } + return "xcodebuild" + } + + String getAltool() { + return getPath() + "/Contents/Applications/Application Loader" + + ".app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" + } + + String getXcrun() { + return getPath() + XCODE_CONTENT_XC_RUN + } + + String getSimctl() { + return getPath() + "/$XCODE_CONTENT_DEVELOPER/usr/bin/simctl" + } + + @Override + String toString() { + return "Xcode{" + + "xcodePath='" + xcodePath + '\'' + + ", version=" + version + + '}' + } } From dfb81ad1a4cce71f6e187b0b145de617cc097bfd Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 15:36:56 +0100 Subject: [PATCH 030/121] Fix unit tests --- .../src/main/groovy/org/openbakery/XcodePlugin.groovy | 10 ++++------ .../XcodeBuildArchiveTaskSpecification.groovy | 1 - .../org/openbakery/XcodePluginSpecification.groovy | 9 +++++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index a7851c8e..aa7ce012 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -602,13 +602,11 @@ class XcodePlugin implements Plugin { private configureCarthageDependencies(Project project) { CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CARTHAGE_BOOTSTRAP_TASK_NAME) - if (bootStrapTask.hasCartFile()) { - addDependencyToBuild(project, bootStrapTask) + addDependencyToBuild(project, bootStrapTask) - project.getTasks() - .getByName(BasePlugin.CLEAN_TASK_NAME) - .dependsOn(project.getTasks().getByName(CARTHAGE_CLEAN_TASK_NAME)) - } + project.getTasks() + .getByName(BasePlugin.CLEAN_TASK_NAME) + .dependsOn(project.getTasks().getByName(CARTHAGE_CLEAN_TASK_NAME)) } private void configureOCLint(Project project) { diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy index f84d1752..9b721dcf 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy @@ -33,7 +33,6 @@ class XcodeBuildArchiveTaskSpecification extends Specification { PlistHelperStub plistHelper = new PlistHelperStub() def setup() { - String tmpName = "gradle-xcodebuild-" + RandomStringUtils.randomAlphanumeric(5) projectDir = new File(System.getProperty("java.io.tmpdir"), tmpName) project = ProjectBuilder.builder().withProjectDir(projectDir).build() diff --git a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy index 463729a4..f505a273 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy @@ -286,7 +286,7 @@ class XcodePluginSpecification extends Specification { project.tasks.findByName('carthageUpdate') instanceof CarthageUpdateTask } - def "xcodebuild has carthage dependency"() { + def "xcodebuild has carthage bootstrap dependency"() { when: File projectDir = new File("../example/iOS/Example") project = ProjectBuilder.builder().withProjectDir(projectDir).build() @@ -298,7 +298,7 @@ class XcodePluginSpecification extends Specification { then: - task.getTaskDependencies().getDependencies() contains(project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME)) + task.getTaskDependencies().getDependencies() contains(project.getTasks().getByName(XcodePlugin.CARTHAGE_BOOTSTRAP_TASK_NAME)) } @@ -307,6 +307,11 @@ class XcodePluginSpecification extends Specification { project.tasks.findByName('carthageClean') instanceof CarthageCleanTask } + def "has carthage update task"() { + expect: + project.tasks.findByName('carthageUpdate') instanceof CarthageUpdateTask + } + def "clean has carthage clean dependency"() { when: File projectDir = new File("../example/iOS/Example") From d671dab13e0108d43b1fc3325f31941065280b4e Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 15:52:50 +0100 Subject: [PATCH 031/121] Path fix for MacOS --- .../XcodeBuildPluginExtension.groovy | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 51efa3b3..e169cb11 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -322,18 +322,21 @@ class XcodeBuildPluginExtension { // should be removed an replaced by the xcodebuildParameters.outputPath File getOutputPath() { - String path = getConfiguration() + "-" - if (type == Type.iOS) { - if (simulator) { - path += PathHelper.IPHONE_SIMULATOR - } else { - path += PathHelper.IPHONE_OS - } - } else if (type == Type.tvOS) { - if (simulator) { - path += PathHelper.APPLE_TV_SIMULATOR - } else { - path += PathHelper.APPLE_TV_OS + String path = getConfiguration() + if (type != Type.macOS) { + path += "-" + if (type == Type.iOS) { + if (simulator) { + path += PathHelper.IPHONE_SIMULATOR + } else { + path += PathHelper.IPHONE_OS + } + } else if (type == Type.tvOS) { + if (simulator) { + path += PathHelper.APPLE_TV_SIMULATOR + } else { + path += PathHelper.APPLE_TV_OS + } } } return new File(getSymRoot(), path) From fa2d5fbc011759a62f9ee5c0aad1062feedd6d77 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 16:18:01 +0100 Subject: [PATCH 032/121] Remove compilestatic for now --- .../groovy/org/openbakery/simulators/SimulatorControl.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index 40a18300..b7dc8fb0 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -10,7 +10,6 @@ import org.openbakery.xcode.Xcode import org.slf4j.Logger import org.slf4j.LoggerFactory -@CompileStatic class SimulatorControl { From 55702e5aed11ac9ea3130fdc1e4114722c0c3f6e Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 17:10:57 +0100 Subject: [PATCH 033/121] More fixes --- .../simulators/SimulatorControl.groovy | 8 ++++---- .../simulators/SimulatorStartTask.groovy | 17 ++++++----------- .../SimulatorStartTaskSpecification.groovy | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy index b7dc8fb0..67f0d6ed 100644 --- a/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy +++ b/libxcode/src/main/groovy/org/openbakery/simulators/SimulatorControl.groovy @@ -1,6 +1,5 @@ package org.openbakery.simulators -import groovy.transform.CompileStatic import org.openbakery.CommandRunner import org.openbakery.CommandRunnerException import org.openbakery.xcode.Destination @@ -152,7 +151,6 @@ class SimulatorControl { return null } - public void waitForDevice(SimulatorDevice device, int timeoutMS = 10000) { def start = System.currentTimeMillis() while ((System.currentTimeMillis() - start) < timeoutMS) { @@ -225,8 +223,10 @@ class SimulatorControl { Optional getDevice(final Destination destination) { return getRuntime(destination) - .map { runtime -> getDevices(runtime) - .find { device -> device.name.equalsIgnoreCase(destination.name) } } + .map { runtime -> + getDevices(runtime) + .find { device -> device.name.equalsIgnoreCase(destination.name) } + } } SimulatorDevice getDeviceWithIdentifier(String identifier) { diff --git a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy index e166a9f8..b79a4f54 100644 --- a/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/simulators/SimulatorStartTask.groovy @@ -1,7 +1,6 @@ package org.openbakery.simulators import org.gradle.api.tasks.TaskAction -import org.openbakery.xcode.Destination class SimulatorStartTask extends AbstractSimulatorTask { @@ -12,15 +11,11 @@ class SimulatorStartTask extends AbstractSimulatorTask { @TaskAction void run() { - - - Destination destination = getDestination() - - Optional device = simulatorControl.getDevice(destination) - if (device.present) { - simulatorControl.killAll() - simulatorControl.runDevice(device) - simulatorControl.waitForDevice(device) - } + simulatorControl.getDevice(getDestination()) + .ifPresent { device -> + simulatorControl.killAll() + simulatorControl.runDevice(device) + simulatorControl.waitForDevice(device) + } } } diff --git a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy index 40237eb0..06fd1e90 100644 --- a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorStartTaskSpecification.groovy @@ -95,7 +95,7 @@ class SimulatorStartTaskSpecification extends Specification { then: 1 * simulatorControl.getDevice((Destination) _) >> { arguments -> destination = arguments[0] - return devices9_1[0] + return Optional.of(devices9_1[0]) } destination != null destination.name == 'iPhone 6s' From c4e507aac17d01e3b141e2b267f9ddfebe365cb1 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 19 Apr 2018 17:41:13 +0100 Subject: [PATCH 034/121] Enable simulator for the test --- .../org/openbakery/XcodeBuildForTestTaskSpecification.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildForTestTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildForTestTaskSpecification.groovy index 3b5081d9..07a951b4 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildForTestTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildForTestTaskSpecification.groovy @@ -170,6 +170,7 @@ class XcodeBuildForTestTaskSpecification extends Specification { def "xcodebuild has all available tvOS destinations"() { when: + xcodeBuildForTestTask.parameters.simulator = true xcodeBuildForTestTask.parameters.type = Type.tvOS def destinations = xcodeBuildForTestTask.xcodebuild.destinations From f61e16748ec8558155ab29a2fcdfc336fb2dc24f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 20 Apr 2018 20:25:25 +0100 Subject: [PATCH 035/121] Fix the Swiftsupport path for TvOS --- .../openbakery/XcodeBuildArchiveTask.groovy | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 61b94526..99d07491 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -46,14 +46,12 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } - - def getiOSIcons() { ArrayList icons = new ArrayList<>(); File applicationBundle = parameters.applicationBundle def fileList = applicationBundle.list( - [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png + [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png ).toList() def applicationPath = "Applications/" + parameters.applicationBundleName @@ -67,7 +65,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } def getMacOSXIcons() { - File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") + File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") ArrayList icons = new ArrayList<>(); def icnsFileName = plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile") @@ -83,7 +81,6 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } - def getValueFromBundleInfoPlist(File bundle, String key) { File appInfoPlist if (parameters.type == Type.macOS) { @@ -160,7 +157,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { content.append(" CreationDate\n") content.append(" " + creationDate + "\n") content.append(" Name\n") - content.append(" " + name + "\n") + content.append(" " + name + "\n") content.append(" SchemeName\n") content.append(" " + schemeName + "\n") content.append("\n") @@ -171,7 +168,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } - def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { + def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") if (frameworksPath.exists()) { @@ -184,7 +181,10 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { logger.debug("swiftlibs to add: {}", libNames); - File swiftLibs = new File(xcodebuild.getToolchainDirectory(), "usr/lib/swift/iphoneos") + File swiftLibs = new File(xcodebuild.getToolchainDirectory(), + "usr/lib/swift/" + getSwiftLibFolderName()) + + logger.debug("swiftlibs to add: {}", swiftLibs); swiftLibs.eachFile() { logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) @@ -196,14 +196,32 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } + public String getSwiftLibFolderName() { + String result + switch (parameters.type) { + case Type.tvOS: + result = "appletvos" + break + + case Type.iOS: + result = "iphoneos" + break + + default: + break + } + + return result + } + def getSwiftSupportDirectory() { def swiftSupportPath = "SwiftSupport" if (xcode.version.major > 6) { - swiftSupportPath += "/iphoneos" + swiftSupportPath += "/" + getSwiftLibFolderName() } - File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath); + File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) if (!swiftSupportDirectory.exists()) { swiftSupportDirectory.mkdirs() } @@ -223,7 +241,6 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { deleteDirectoryIfEmpty(appPath, "Frameworks") - } def deleteFrameworksInExtension(File applicationsDirectory) { @@ -367,7 +384,6 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { return } - // create xcarchive // copy application bundle copy(parameters.applicationBundle, getApplicationsDirectory()) @@ -427,7 +443,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { if (!plugins.exists()) { return } - plugins.eachFile (FileType.DIRECTORIES) { file -> + plugins.eachFile(FileType.DIRECTORIES) { file -> if (file.toString().endsWith("xctest")) { FileUtils.deleteDirectory(file) return true @@ -486,7 +502,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { File getArchiveDirectory() { - def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName + def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName if (project.xcodebuild.bundleNameSuffix != null) { archiveDirectoryName += project.xcodebuild.bundleNameSuffix From d30efdf525125b50fd6916d4ed8e87aa4fd92268 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 23 Apr 2018 16:04:09 +0100 Subject: [PATCH 036/121] Remove unnecessary dylib from bundle --- .../groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 99d07491..0de2d1af 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -406,6 +406,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } File applicationsDirectory = getApplicationsDirectory() + File archiveDirectory = getArchiveDirectory() createInfoPlist(archiveDirectory) createFrameworks(archiveDirectory, xcodebuild) @@ -417,6 +418,8 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) convertInfoPlistToBinary(applicationFolder) + + removeUnneededDylibsFromBundle(applicationFolder) } logger.debug("create archive done") @@ -438,6 +441,13 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } + def deleteXCTestIfExists(File applicationsDirectory) { File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") if (!plugins.exists()) { From a86fc0268d7af6b17dac481ccd949208f9a217cf Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 23 Apr 2018 16:14:47 +0100 Subject: [PATCH 037/121] Fix indentations --- build.gradle | 2 +- .../org/openbakery/XcodeBuildArchiveTask.groovy | 16 ++++++++-------- .../org/openbakery/packaging/PackageTask.groovy | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 00092018..afccbb92 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ allprojects { apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' - def versionNumber = "0.2.6-SNAPSHOT" + def versionNumber = "0.2.8-SNAPSHOT" if (project.hasProperty("versionNumber")) { versionNumber = project.versionNumber diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 0de2d1af..46a6c76c 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -184,7 +184,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { File swiftLibs = new File(xcodebuild.getToolchainDirectory(), "usr/lib/swift/" + getSwiftLibFolderName()) - logger.debug("swiftlibs to add: {}", swiftLibs); + logger.debug("swiftlibs to add: {}", swiftLibs); swiftLibs.eachFile() { logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) @@ -419,7 +419,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) convertInfoPlistToBinary(applicationFolder) - removeUnneededDylibsFromBundle(applicationFolder) + removeUnneededDylibsFromBundle(applicationFolder) } logger.debug("create archive done") @@ -441,12 +441,12 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } - def removeUnneededDylibsFromBundle(File bundle) { - File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") - if (libswiftRemoteMirror.exists()) { - libswiftRemoteMirror.delete() - } - } + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } def deleteXCTestIfExists(File applicationsDirectory) { File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index fc0eee3b..3afbd362 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -287,9 +287,9 @@ class PackageTask extends AbstractDistributeTask { } } - private File getInfoPlistFile() { + private File getInfoPlistFile() { return new File(getAppContentPath() + "Info.plist") - } + } private String getAppContentPath() { From 4dafb800e9378dbd11ca5e4002afc66afd60cf78 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 23 Apr 2018 16:19:04 +0100 Subject: [PATCH 038/121] Add a TODO --- .../src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 46a6c76c..b4b56eb5 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -441,6 +441,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } + // TODO: Define a `exportOptionsPlist` to avoid that kind of issue def removeUnneededDylibsFromBundle(File bundle) { File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") if (libswiftRemoteMirror.exists()) { From 82051740b048bc28b2e6fdc37f4b6e3e0a341567 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 24 Apr 2018 09:29:49 +0100 Subject: [PATCH 039/121] --wip-- [skip ci] --- .../openbakery/XcodeBuildArchiveTask.groovy | 976 +++++++++--------- 1 file changed, 481 insertions(+), 495 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index b4b56eb5..50d9d9bd 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -17,513 +17,499 @@ package org.openbakery import groovy.io.FileType import org.apache.commons.io.FileUtils +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.xcode.Type import org.openbakery.xcode.Extension +import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild +import java.util.regex.Pattern + import static groovy.io.FileType.FILES class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { - public static final String ARCHIVE_FOLDER = "archive" - - XcodeBuildArchiveTask() { - super() - - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) - // when creating an xcarchive for iOS then the provisioning profile is need for the team id so that the entitlements is setup properly - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - this.description = "Prepare the app bundle that it can be archive" - } - - - def getOutputDirectory() { - def archiveDirectory = new File(project.getBuildDir(), ARCHIVE_FOLDER) - archiveDirectory.mkdirs() - return archiveDirectory - } - - - def getiOSIcons() { - ArrayList icons = new ArrayList<>(); - - File applicationBundle = parameters.applicationBundle - def fileList = applicationBundle.list( - [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png - ).toList() - - def applicationPath = "Applications/" + parameters.applicationBundleName - - for (String item in fileList) { - icons.add(applicationPath + "/" + item) - } - - - return icons - } - - def getMacOSXIcons() { - File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") - ArrayList icons = new ArrayList<>(); - - def icnsFileName = plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile") - - if (icnsFileName == null || icnsFileName == "") { - return icons - } - - def iconPath = "Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + icnsFileName + ".icns" - icons.add(iconPath) - - return icons - } - - - def getValueFromBundleInfoPlist(File bundle, String key) { - File appInfoPlist - if (parameters.type == Type.macOS) { - appInfoPlist = new File(bundle, "Contents/Info.plist") - } else { - appInfoPlist = new File(bundle, "Info.plist") - } - return plistHelper.getValueFromPlist(appInfoPlist, key) - } - - - def createInfoPlist(def applicationsDirectory) { - - StringBuilder content = new StringBuilder(); - - - def name = parameters.bundleName - def schemeName = name - def applicationPath = "Applications/" + parameters.applicationBundleName - def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") - int time = System.currentTimeMillis() / 1000; - - def creationDate = formatDate(new Date()); - - def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") - def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") - - List icons - if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { - icons = getiOSIcons() - } else { - icons = getMacOSXIcons() - } - - content.append("\n") - content.append("\n") - content.append("\n") - content.append("\n") - content.append(" ApplicationProperties\n") - content.append(" \n") - content.append(" ApplicationPath\n") - content.append(" " + applicationPath + "\n") - content.append(" CFBundleIdentifier\n") - content.append(" " + bundleIdentifier + "\n") - - if (shortBundleVersion != null) { - content.append(" CFBundleShortVersionString\n") - content.append(" " + shortBundleVersion + "\n") - } - - if (bundleVersion != null) { - content.append(" CFBundleVersion\n") - content.append(" " + bundleVersion + "\n") - } - - if (getSigningIdentity()) { - content.append(" SigningIdentity\n") - content.append(" " + getSigningIdentity() + "\n") - - } - - if (icons.size() > 0) { - content.append(" IconPaths\n") - content.append(" \n") - for (String icon : icons) { - content.append(" " + icon + "\n") - } - content.append(" \n") - } - - content.append(" \n") - content.append(" ArchiveVersion\n") - content.append(" 2\n") - content.append(" CreationDate\n") - content.append(" " + creationDate + "\n") - content.append(" Name\n") - content.append(" " + name + "\n") - content.append(" SchemeName\n") - content.append(" " + schemeName + "\n") - content.append("\n") - content.append("") - - File infoPlist = new File(applicationsDirectory, "Info.plist") - FileUtils.writeStringToFile(infoPlist, content.toString()) - } - - - def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { - - File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") - if (frameworksPath.exists()) { - - - def libNames = [] - frameworksPath.eachFile() { - libNames.add(it.getName()) - } - - logger.debug("swiftlibs to add: {}", libNames); + public static final String ARCHIVE_FOLDER = "archive" + + private static final Pattern ICON_FILE_MATCHER = ~/Icon(-\d+)??\.png/ + + XcodeBuildArchiveTask() { + super() + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) + // when creating an xcarchive for iOS then the provisioning profile is need for the team id so that the entitlements is setup properly + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + this.description = "Prepare the app bundle that it can be archive" + } + + @OutputDirectory + File getOutputDirectory() { + def archiveDirectory = new File(project.getBuildDir(), ARCHIVE_FOLDER) + archiveDirectory.mkdirs() + return archiveDirectory + } + + + private ArrayList getiOSIcons() { + return parameters.applicationBundle + .list() + .findAll { it.matches(ICON_FILE_MATCHER) } + .collect { "Applications/" + parameters.applicationBundleName + "/" + it } + } + + ArrayList getMacOSXIcons() { + File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") + return Optional.ofNullable(plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile")) + .filter { it -> return !it.empty } + .map { it -> ["Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + it + ".icns"] } + .orElse([]) + } + + def getValueFromBundleInfoPlist(File bundle, String key) { + File appInfoPlist + if (parameters.type == Type.macOS) { + appInfoPlist = new File(bundle, "Contents/Info.plist") + } else { + appInfoPlist = new File(bundle, "Info.plist") + } + return plistHelper.getValueFromPlist(appInfoPlist, key) + } + + + def createInfoPlist(def applicationsDirectory) { + + StringBuilder content = new StringBuilder(); + + + def name = parameters.bundleName + def schemeName = name + def applicationPath = "Applications/" + parameters.applicationBundleName + def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") + int time = System.currentTimeMillis() / 1000; + + def creationDate = formatDate(new Date()); + + def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") + def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") + + List icons + if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { + icons = getiOSIcons() + } else { + icons = getMacOSXIcons() + } + + content.append("\n") + content.append("\n") + content.append("\n") + content.append("\n") + content.append(" ApplicationProperties\n") + content.append(" \n") + content.append(" ApplicationPath\n") + content.append(" " + applicationPath + "\n") + content.append(" CFBundleIdentifier\n") + content.append(" " + bundleIdentifier + "\n") + + if (shortBundleVersion != null) { + content.append(" CFBundleShortVersionString\n") + content.append(" " + shortBundleVersion + "\n") + } + + if (bundleVersion != null) { + content.append(" CFBundleVersion\n") + content.append(" " + bundleVersion + "\n") + } + + if (getSigningIdentity()) { + content.append(" SigningIdentity\n") + content.append(" " + getSigningIdentity() + "\n") + + } + + if (icons.size() > 0) { + content.append(" IconPaths\n") + content.append(" \n") + for (String icon : icons) { + content.append(" " + icon + "\n") + } + content.append(" \n") + } + + content.append(" \n") + content.append(" ArchiveVersion\n") + content.append(" 2\n") + content.append(" CreationDate\n") + content.append(" " + creationDate + "\n") + content.append(" Name\n") + content.append(" " + name + "\n") + content.append(" SchemeName\n") + content.append(" " + schemeName + "\n") + content.append("\n") + content.append("") + + File infoPlist = new File(applicationsDirectory, "Info.plist") + FileUtils.writeStringToFile(infoPlist, content.toString()) + } + + + def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { + + File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") + if (frameworksPath.exists()) { + + + def libNames = [] + frameworksPath.eachFile() { + libNames.add(it.getName()) + } + + logger.debug("swiftlibs to add: {}", libNames); - File swiftLibs = new File(xcodebuild.getToolchainDirectory(), - "usr/lib/swift/" + getSwiftLibFolderName()) - - logger.debug("swiftlibs to add: {}", swiftLibs); - - swiftLibs.eachFile() { - logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) - if (libNames.contains(it.name)) { - copy(it, getSwiftSupportDirectory()) - } - } - } - - } - - public String getSwiftLibFolderName() { - String result - switch (parameters.type) { - case Type.tvOS: - result = "appletvos" - break - - case Type.iOS: - result = "iphoneos" - break - - default: - break - } - - return result - } - - def getSwiftSupportDirectory() { - def swiftSupportPath = "SwiftSupport" - - if (xcode.version.major > 6) { - swiftSupportPath += "/" + getSwiftLibFolderName() - } - - File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) - if (!swiftSupportDirectory.exists()) { - swiftSupportDirectory.mkdirs() - } - return swiftSupportDirectory - } - - def deleteDirectoryIfEmpty(File base, String child) { - File directory = new File(base, child) - if (directory.exists() && directory.list().length == 0) { - directory.deleteDir(); - } - } - - def deleteEmptyFrameworks(File applicationsDirectory) { - // if frameworks directory is emtpy - File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) - deleteDirectoryIfEmpty(appPath, "Frameworks") - - - } - - def deleteFrameworksInExtension(File applicationsDirectory) { - - - File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") - if (!plugins.exists()) { - return - } - - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith(".appex")) { - File frameworkDirectory = new File(file, "Frameworks"); - if (frameworkDirectory.exists()) { - FileUtils.deleteDirectory(frameworkDirectory) - } - } - } - - } - - - def copyDsyms(File archiveDirectory, File dSymDirectory) { - - archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> - if (directory.toString().toLowerCase().endsWith(".dsym")) { - copy(directory, dSymDirectory) - } - } - - } - - def createEntitlements(File bundle) { - - if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { - logger.warn("Entitlements handling is only implemented for iOS and tvOS!") - return - } - - String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") - if (bundleIdentifier == null) { - logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) - return - } - BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) - if (buildConfiguration == null) { - logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) - return - } - - File destinationDirectory = getDestinationDirectoryForBundle(bundle) - if (buildConfiguration.entitlements) { - File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") - FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) - modifyEntitlementsFile(entitlementFile, bundleIdentifier) - } - } - - def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { - if (!entitlementFile.exists()) { - logger.warn("Entitlements File does not exist {}", entitlementFile) - return - } - - String applicationIdentifier = "UNKNOWN00ID"; // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback - File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) - if (provisioningProfile != null && provisioningProfile.exists()) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) - applicationIdentifier = reader.getApplicationIdentifierPrefix() - } - - plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) - - List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") - - if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { - def modifiedKeychainAccessGroups = [] - keychainAccessGroups.each() { group -> - modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") - } - plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) - } - } - - def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { - String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") - if (extensionIdentifier == null) { - logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) - return - } - - Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) - if (extension == null) { - logger.warn("Extension type not supported", extensionIdentifier) - return - } - - switch (extension) { - case Extension.sticker: - File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") - if (supportDirectory.mkdirs()) { - File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") - copy(stub, supportDirectory) - } - break - default: - break - } - } - - @TaskAction - def archive() { - parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) - if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { - logger.debug("Create zip archive") - - // create zip archive - String zipFileName = parameters.bundleName - if (project.xcodebuild.bundleNameSuffix != null) { - zipFileName += project.xcodebuild.bundleNameSuffix - } - zipFileName += ".zip" - - def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) - def baseDirectory = parameters.applicationBundle.parentFile - - createZip(zipFile, baseDirectory, parameters.applicationBundle) - return - } - - logger.debug("Create xcarchive") - Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) - - if (project.xcodebuild.useXcodebuildArchive) { - - File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - commandRunner.setOutputFile(outputFile) - - xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) - - return - } - - // create xcarchive - // copy application bundle - copy(parameters.applicationBundle, getApplicationsDirectory()) - - File onDemandResources = new File(parameters.outputPath, "OnDemandResources") - if (onDemandResources.exists()) { - copy(onDemandResources, getProductsDirectory()) - } - - // copy onDemandResources - - def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") - dSymDirectory.mkdirs() - copyDsyms(parameters.outputPath, dSymDirectory) - - List appBundles = getAppBundles(parameters.outputPath) - for (File bundle : appBundles) { - createEntitlements(bundle) - createExtensionSupportDirectory(bundle, xcodebuild) - } - - File applicationsDirectory = getApplicationsDirectory() - - File archiveDirectory = getArchiveDirectory() - createInfoPlist(archiveDirectory) - createFrameworks(archiveDirectory, xcodebuild) - deleteEmptyFrameworks(archiveDirectory) - deleteXCTestIfExists(applicationsDirectory) - deleteFrameworksInExtension(applicationsDirectory) - copyBCSymbolMaps(archiveDirectory) - - if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { - File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) - convertInfoPlistToBinary(applicationFolder) - - removeUnneededDylibsFromBundle(applicationFolder) - } - - logger.debug("create archive done") - } - - def copyBCSymbolMaps(File archiveDirectory) { - if (!parameters.bitcode) { - logger.debug("bitcode is not activated, so to not create BCSymbolMaps") - return - } - File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") - bcSymbolMapsDirectory.mkdirs() - - parameters.outputPath.eachFileRecurse { file -> - if (file.toString().endsWith(".bcsymbolmap")) { - FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) - } - } - - } + File swiftLibs = new File(xcodebuild.getToolchainDirectory(), + "usr/lib/swift/" + getSwiftLibFolderName()) + + logger.debug("swiftlibs to add: {}", swiftLibs); + + swiftLibs.eachFile() { + logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) + if (libNames.contains(it.name)) { + copy(it, getSwiftSupportDirectory()) + } + } + } + + } + + public String getSwiftLibFolderName() { + String result + switch (parameters.type) { + case Type.tvOS: + result = "appletvos" + break + + case Type.iOS: + result = "iphoneos" + break + + default: + break + } + + return result + } + + def getSwiftSupportDirectory() { + def swiftSupportPath = "SwiftSupport" + + if (xcode.version.major > 6) { + swiftSupportPath += "/" + getSwiftLibFolderName() + } + + File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) + if (!swiftSupportDirectory.exists()) { + swiftSupportDirectory.mkdirs() + } + return swiftSupportDirectory + } + + def deleteDirectoryIfEmpty(File base, String child) { + File directory = new File(base, child) + if (directory.exists() && directory.list().length == 0) { + directory.deleteDir(); + } + } + + def deleteEmptyFrameworks(File applicationsDirectory) { + // if frameworks directory is emtpy + File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) + deleteDirectoryIfEmpty(appPath, "Frameworks") + + + } + + def deleteFrameworksInExtension(File applicationsDirectory) { + + + File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") + if (!plugins.exists()) { + return + } + + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith(".appex")) { + File frameworkDirectory = new File(file, "Frameworks"); + if (frameworkDirectory.exists()) { + FileUtils.deleteDirectory(frameworkDirectory) + } + } + } + + } + + + def copyDsyms(File archiveDirectory, File dSymDirectory) { + + archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> + if (directory.toString().toLowerCase().endsWith(".dsym")) { + copy(directory, dSymDirectory) + } + } + + } + + def createEntitlements(File bundle) { + + if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { + logger.warn("Entitlements handling is only implemented for iOS and tvOS!") + return + } + + String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") + if (bundleIdentifier == null) { + logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) + return + } + BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) + if (buildConfiguration == null) { + logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) + return + } + + File destinationDirectory = getDestinationDirectoryForBundle(bundle) + if (buildConfiguration.entitlements) { + File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") + FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) + modifyEntitlementsFile(entitlementFile, bundleIdentifier) + } + } + + def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { + if (!entitlementFile.exists()) { + logger.warn("Entitlements File does not exist {}", entitlementFile) + return + } + + String applicationIdentifier = "UNKNOWN00ID"; + // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback + File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) + if (provisioningProfile != null && provisioningProfile.exists()) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) + applicationIdentifier = reader.getApplicationIdentifierPrefix() + } + + plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) + + List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") + + if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { + def modifiedKeychainAccessGroups = [] + keychainAccessGroups.each() { group -> + modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") + } + plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) + } + } + + def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { + String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") + if (extensionIdentifier == null) { + logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) + return + } + + Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) + if (extension == null) { + logger.warn("Extension type not supported", extensionIdentifier) + return + } + + switch (extension) { + case Extension.sticker: + File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") + if (supportDirectory.mkdirs()) { + File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") + copy(stub, supportDirectory) + } + break + default: + break + } + } + + @TaskAction + def archive() { + parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) + if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { + logger.debug("Create zip archive") + + // create zip archive + String zipFileName = parameters.bundleName + if (project.xcodebuild.bundleNameSuffix != null) { + zipFileName += project.xcodebuild.bundleNameSuffix + } + zipFileName += ".zip" + + def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) + def baseDirectory = parameters.applicationBundle.parentFile + + createZip(zipFile, baseDirectory, parameters.applicationBundle) + return + } + + logger.debug("Create xcarchive") + Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) + + if (project.xcodebuild.useXcodebuildArchive) { + + File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + commandRunner.setOutputFile(outputFile) + + xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) + + return + } + + // create xcarchive + // copy application bundle + copy(parameters.applicationBundle, getApplicationsDirectory()) + + File onDemandResources = new File(parameters.outputPath, "OnDemandResources") + if (onDemandResources.exists()) { + copy(onDemandResources, getProductsDirectory()) + } + + // copy onDemandResources + + def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") + dSymDirectory.mkdirs() + copyDsyms(parameters.outputPath, dSymDirectory) + + List appBundles = getAppBundles(parameters.outputPath) + for (File bundle : appBundles) { + createEntitlements(bundle) + createExtensionSupportDirectory(bundle, xcodebuild) + } + + File applicationsDirectory = getApplicationsDirectory() + + File archiveDirectory = getArchiveDirectory() + createInfoPlist(archiveDirectory) + createFrameworks(archiveDirectory, xcodebuild) + deleteEmptyFrameworks(archiveDirectory) + deleteXCTestIfExists(applicationsDirectory) + deleteFrameworksInExtension(applicationsDirectory) + copyBCSymbolMaps(archiveDirectory) + + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { + File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) + convertInfoPlistToBinary(applicationFolder) + + removeUnneededDylibsFromBundle(applicationFolder) + } + + logger.debug("create archive done") + } + + def copyBCSymbolMaps(File archiveDirectory) { + if (!parameters.bitcode) { + logger.debug("bitcode is not activated, so to not create BCSymbolMaps") + return + } + File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") + bcSymbolMapsDirectory.mkdirs() + + parameters.outputPath.eachFileRecurse { file -> + if (file.toString().endsWith(".bcsymbolmap")) { + FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) + } + } + + } // TODO: Define a `exportOptionsPlist` to avoid that kind of issue - def removeUnneededDylibsFromBundle(File bundle) { - File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") - if (libswiftRemoteMirror.exists()) { - libswiftRemoteMirror.delete() - } - } - - def deleteXCTestIfExists(File applicationsDirectory) { - File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") - if (!plugins.exists()) { - return - } - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith("xctest")) { - FileUtils.deleteDirectory(file) - return true - } - } - } - - File getProductsDirectory() { - File productsDirectory = new File(getArchiveDirectory(), "Products") - productsDirectory.mkdirs() - return productsDirectory - } - - File getApplicationsDirectory() { - File applicationsDirectory = new File(getProductsDirectory(), "Applications") - applicationsDirectory.mkdirs() - return applicationsDirectory - } - - File getDestinationDirectoryForBundle(File bundle) { - String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); - return new File(getApplicationsDirectory(), relative) - } - - def convertInfoPlistToBinary(File archiveDirectory) { - - archiveDirectory.eachFileRecurse(FILES) { - if (it.name.endsWith('.plist')) { - logger.debug("convert plist to binary {}", it) - def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] - try { - commandRunner.run(commandList) - } catch (CommandRunnerException ex) { - logger.lifecycle("Unable to convert!") - } - } - } - - } - - - def removeResourceRules(File appDirectory) { - - File resourceRules = new File(appDirectory, "ResourceRules.plist") - logger.lifecycle("delete {}", resourceRules) - if (resourceRules.exists()) { - resourceRules.delete() - } - - logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) - - setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") - - } - - - File getArchiveDirectory() { - - def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName - - if (project.xcodebuild.bundleNameSuffix != null) { - archiveDirectoryName += project.xcodebuild.bundleNameSuffix - } - archiveDirectoryName += ".xcarchive" - - def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) - archiveDirectory.mkdirs() - return archiveDirectory - } + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } + + def deleteXCTestIfExists(File applicationsDirectory) { + File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") + if (!plugins.exists()) { + return + } + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith("xctest")) { + FileUtils.deleteDirectory(file) + return true + } + } + } + + File getProductsDirectory() { + File productsDirectory = new File(getArchiveDirectory(), "Products") + productsDirectory.mkdirs() + return productsDirectory + } + + File getApplicationsDirectory() { + File applicationsDirectory = new File(getProductsDirectory(), "Applications") + applicationsDirectory.mkdirs() + return applicationsDirectory + } + + File getDestinationDirectoryForBundle(File bundle) { + String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); + return new File(getApplicationsDirectory(), relative) + } + + def convertInfoPlistToBinary(File archiveDirectory) { + + archiveDirectory.eachFileRecurse(FILES) { + if (it.name.endsWith('.plist')) { + logger.debug("convert plist to binary {}", it) + def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] + try { + commandRunner.run(commandList) + } catch (CommandRunnerException ex) { + logger.lifecycle("Unable to convert!") + } + } + } + + } + + + def removeResourceRules(File appDirectory) { + + File resourceRules = new File(appDirectory, "ResourceRules.plist") + logger.lifecycle("delete {}", resourceRules) + if (resourceRules.exists()) { + resourceRules.delete() + } + + logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) + + setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") + + } + + + File getArchiveDirectory() { + + def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName + + if (project.xcodebuild.bundleNameSuffix != null) { + archiveDirectoryName += project.xcodebuild.bundleNameSuffix + } + archiveDirectoryName += ".xcarchive" + + def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) + archiveDirectory.mkdirs() + return archiveDirectory + } } From b611da85c2359aa5921036996261e4f0625e8355 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 24 Apr 2018 13:40:18 +0100 Subject: [PATCH 040/121] --wip-- [skip ci] --- .../org/openbakery/xcode/Xcodebuild.groovy | 667 +++++----- .../openbakery/XcodeBuildArchiveTask.groovy | 169 +-- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 95 ++ .../groovy/org/openbakery/XcodePlugin.groovy | 1078 +++++++++-------- 4 files changed, 1074 insertions(+), 935 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index 86fdd945..c3fd989c 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -5,329 +5,346 @@ import org.openbakery.output.OutputAppender class Xcodebuild { - CommandRunner commandRunner - - HashMap buildSettings = null - - File projectDirectory - String xcodePath - Xcode xcode - XcodebuildParameters parameters - List destinations - - - - public Xcodebuild(File projectDirectory, CommandRunner commandRunner, Xcode xcode, XcodebuildParameters parameters, List destinations) { - this.projectDirectory = projectDirectory - this.commandRunner = commandRunner - this.xcode = xcode - this.parameters = parameters - this.destinations = destinations - } - - def validateParameters(OutputAppender outputAppender, Map environment) { - if (this.projectDirectory == null) { - throw new IllegalArgumentException("projectDirectory must not be null"); - } - - if (outputAppender == null) { - throw new IllegalArgumentException("outputAppender must not be null"); - } - - if (parameters.scheme == null && parameters.target == null) { - throw new IllegalArgumentException("No 'scheme' or 'target' specified, so do not know what to build"); - } - } - - def execute(OutputAppender outputAppender, Map environment) { - validateParameters(outputAppender, environment) - def commandList = [] - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addDestinationSettingsForBuild(commandList) - - commandRunner.run(projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def commandListForTest(OutputAppender outputAppender, Map environment) { - validateParameters(outputAppender, environment) - def commandList = [] - commandList << 'script' << '-q' << '/dev/null' - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addDestinationSettingsForTest(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addCoverageSettings(commandList) - return commandList - } - - def executeTest(OutputAppender outputAppender, Map environment) { - def commandList = commandListForTest(outputAppender, environment) - commandList << "test" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def executeBuildForTesting(OutputAppender outputAppender, Map environment) { - def commandList = commandListForTest(outputAppender, environment) - commandList << "build-for-testing" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def executeTestWithoutBuilding(OutputAppender outputAppender, Map environment) { - - parameters.xctestrun.each { - def commandList = [] - commandList << 'script' << '-q' << '/dev/null' - commandList << xcode.xcodebuild - addDestinationSettingsForTest(commandList) - commandList.add("-derivedDataPath") - commandList.add(parameters.derivedDataPath.absolutePath) - addAdditionalParameters(commandList) - addCoverageSettings(commandList) - - commandList << "-xctestrun" << it.absolutePath - commandList << "test-without-building" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - - - } - - } - - def executeArchive(OutputAppender outputAppender, Map environment, String archivePath) { - validateParameters(outputAppender, environment) - def commandList = [] - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addDestinationSettingsForBuild(commandList) - commandList << "archive" - commandList << '-archivePath' - commandList << archivePath - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - - def addBuildSettings(ArrayList commandList) { - - commandList << xcode.xcodebuild - - if (parameters.scheme) { - commandList.add("-scheme"); - commandList.add(parameters.scheme); - - if (parameters.workspace != null) { - commandList.add("-workspace") - commandList.add(parameters.workspace) - } - - if (parameters.configuration != null) { - commandList.add("-configuration") - commandList.add(parameters.configuration) - } - - - } else { - commandList.add("-configuration") - commandList.add(parameters.configuration) - - if (parameters.type == Type.macOS) { - commandList.add("-sdk") - commandList.add("macosx") - } - - commandList.add("-target") - commandList.add(parameters.target) - } - - if (parameters.bitcode) { - commandList.add('OTHER_CFLAGS="-fembed-bitcode"') - commandList.add('BITCODE_GENERATION_MODE=bitcode') - } - } - - def addDisableCodeSigning(ArrayList commandList) { - if (parameters.type != Type.macOS && parameters.simulator) { - // if it is a simulator build then do not add the parameters below - return - } - - commandList.add("CODE_SIGN_IDENTITY=") - commandList.add("CODE_SIGNING_REQUIRED=NO") - //commandList.add("CODE_SIGN_ENTITLEMENTS=") - //commandList.add("CODE_SIGNING_ALLOWED=NO") - } - - private boolean isSimulator() { - isSimulatorBuildOf(Type.iOS) || isSimulatorBuildOf(Type.tvOS) - } - - def addBuildPath(ArrayList commandList) { - if (parameters.scheme) { - // add this parameter only if a scheme is set - commandList.add("-derivedDataPath") - commandList.add(parameters.derivedDataPath.absolutePath) - } - commandList.add("DSTROOT=" + parameters.dstRoot.absolutePath) - commandList.add("OBJROOT=" + parameters.objRoot.absolutePath) - commandList.add("SYMROOT=" + parameters.symRoot.absolutePath) - commandList.add("SHARED_PRECOMPS_DIR=" + parameters.sharedPrecompsDir.absolutePath) - } - - def addAdditionalParameters(ArrayList commandList) { - if (parameters.arch != null) { - StringBuilder archs = new StringBuilder("ARCHS="); - for (String singleArch in parameters.arch) { - if (archs.length() > 7) { - archs.append(" "); - } - archs.append(singleArch); - } - commandList.add(archs.toString()); - } - - if (parameters.additionalParameters instanceof List) { - for (String value in parameters.additionalParameters) { - commandList.add(value) - } - } else { - if (parameters.additionalParameters != null) { - commandList.add(parameters.additionalParameters) - } - } - } - - - def addDestinationSettingsForBuild(ArrayList commandList) { - if (isSimulator()) { - Destination destination = this.destinations.last() - commandList.add("-destination") - commandList.add(getDestinationCommandParameter(destination)) - } - if (parameters.type == Type.macOS) { - commandList.add("-destination") - commandList.add("platform=OS X,arch=x86_64") - } - } - - def addDestinationSettingsForTest(ArrayList commandList) { - switch (parameters.type) { - case Type.iOS: - case Type.tvOS: - this.destinations.each { destination -> - commandList.add("-destination") - commandList.add(getDestinationCommandParameter(destination)) - } - break; - - case Type.macOS: - commandList.add("-destination") - commandList.add("platform=OS X,arch=x86_64") - break; - - default: - break; - } - } - - void addCoverageSettings(ArrayList commandList) { - if (xcode.version.major < 7) { - commandList.add("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES") - commandList.add("GCC_GENERATE_TEST_COVERAGE_FILES=YES") - } else { - commandList.add("-enableCodeCoverage") - commandList.add("yes") - } - } - - - boolean isSimulatorBuildOf(Type expectedType) { - if (parameters.type != expectedType) { - return false - } - if (parameters.type != Type.macOS) { - // os x does not have a simulator - return parameters.simulator - } - return false - } - - protected String getDestinationCommandParameter(Destination destination) { - def destinationParameters = [] - - if (destination.platform != null) { - destinationParameters << "platform=" + destination.platform - } - if (destination.id != null) { - destinationParameters << "id=" + destination.id - } else { - if (destination.name != null) { - destinationParameters << "name=" + destination.name - } - /* - if (destination.arch != null && parameters.availableDestinations.platform.equals("OS X")) { - destinationParameters << "arch=" + destination.arch - } - - if (destination.os != null && parameters.availableDestinations.platform.equals("iOS Simulator")) { - destinationParameters << "OS=" + destination.os - } - */ - } - return destinationParameters.join(",") - } - - - String getToolchainDirectory() { - String buildSetting = getBuildSetting("TOOLCHAIN_DIR") - if (buildSetting != null) { - return buildSetting - } - return "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain" - } - - String getPlatformDirectory() { - return getBuildSetting("PLATFORM_DIR") - } - - String loadBuildSettings() { - def commandList = [xcode.xcodebuild, "clean", "-showBuildSettings"] - - if (parameters.scheme != null && parameters.workspace != null) { - commandList.add("-scheme"); - commandList.add(parameters.scheme) - commandList.add("-workspace") - commandList.add(parameters.workspace) - } - - return commandRunner.runWithResult(this.projectDirectory.absolutePath, commandList) - } - - private String getBuildSetting(String key) { - if (buildSettings == null) { - buildSettings = new HashMap<>() - String[] buildSettingsData = loadBuildSettings().split("\n") - for (line in buildSettingsData) { - int index = line.indexOf("=") - if (index > 0) { - String settingsKey = line.substring(0, index).trim() - String settingsValue = line.substring(index + 1, line.length()).trim() - buildSettings.put(settingsKey, settingsValue) - } - } - } - return buildSettings.get(key) - } - - @Override - public String toString() { - return "Xcodebuild{" + - "xcodePath='" + xcodePath + '\'' + - parameters + - '}' - } + CommandRunner commandRunner + + HashMap buildSettings = null + + File projectDirectory + String xcodePath + Xcode xcode + XcodebuildParameters parameters + List destinations + + public static final String ACTION_ARCHIVE = "archive" + public static final String ARGUMENT_SCHEME = "-scheme" + public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" + public static final String ARGUMENT_XCCONFIG = "-xcconfig" + + public Xcodebuild(File projectDirectory, CommandRunner commandRunner, Xcode xcode, XcodebuildParameters parameters, List destinations) { + this.projectDirectory = projectDirectory + this.commandRunner = commandRunner + this.xcode = xcode + this.parameters = parameters + this.destinations = destinations + } + + def validateParameters(OutputAppender outputAppender, Map environment) { + if (this.projectDirectory == null) { + throw new IllegalArgumentException("projectDirectory must not be null"); + } + + if (outputAppender == null) { + throw new IllegalArgumentException("outputAppender must not be null"); + } + + if (parameters.scheme == null && parameters.target == null) { + throw new IllegalArgumentException("No 'scheme' or 'target' specified, so do not know what to build"); + } + } + + public void archive(String scheme, + File outputPath, + File xcconfig) { + assert scheme != null + assert outputPath.exists() && outputPath.isDirectory() + assert xcconfig.exists() && !xcconfig.isDirectory() + + commandRunner.run("xcodebuild", + ACTION_ARCHIVE, + ARGUMENT_SCHEME, scheme, + ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, + ARGUMENT_XCCONFIG, xcconfig.absolutePath) + } + + def execute(OutputAppender outputAppender, Map environment) { + validateParameters(outputAppender, environment) + def commandList = [] + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addDestinationSettingsForBuild(commandList) + + commandRunner.run(projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def commandListForTest(OutputAppender outputAppender, Map environment) { + validateParameters(outputAppender, environment) + def commandList = [] + commandList << 'script' << '-q' << '/dev/null' + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addDestinationSettingsForTest(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addCoverageSettings(commandList) + return commandList + } + + def executeTest(OutputAppender outputAppender, Map environment) { + def commandList = commandListForTest(outputAppender, environment) + commandList << "test" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def executeBuildForTesting(OutputAppender outputAppender, Map environment) { + def commandList = commandListForTest(outputAppender, environment) + commandList << "build-for-testing" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def executeTestWithoutBuilding(OutputAppender outputAppender, Map environment) { + + parameters.xctestrun.each { + def commandList = [] + commandList << 'script' << '-q' << '/dev/null' + commandList << xcode.xcodebuild + addDestinationSettingsForTest(commandList) + commandList.add("-derivedDataPath") + commandList.add(parameters.derivedDataPath.absolutePath) + addAdditionalParameters(commandList) + addCoverageSettings(commandList) + + commandList << "-xctestrun" << it.absolutePath + commandList << "test-without-building" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + + + } + + } + + def executeArchive(OutputAppender outputAppender, Map environment, String archivePath) { + validateParameters(outputAppender, environment) + def commandList = [] + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addDestinationSettingsForBuild(commandList) + commandList << "archive" + commandList << '-archivePath' + commandList << archivePath + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + + def addBuildSettings(ArrayList commandList) { + + commandList << xcode.xcodebuild + + if (parameters.scheme) { + commandList.add("-scheme"); + commandList.add(parameters.scheme); + + if (parameters.workspace != null) { + commandList.add("-workspace") + commandList.add(parameters.workspace) + } + + if (parameters.configuration != null) { + commandList.add("-configuration") + commandList.add(parameters.configuration) + } + + + } else { + commandList.add("-configuration") + commandList.add(parameters.configuration) + + if (parameters.type == Type.macOS) { + commandList.add("-sdk") + commandList.add("macosx") + } + + commandList.add("-target") + commandList.add(parameters.target) + } + + if (parameters.bitcode) { + commandList.add('OTHER_CFLAGS="-fembed-bitcode"') + commandList.add('BITCODE_GENERATION_MODE=bitcode') + } + } + + def addDisableCodeSigning(ArrayList commandList) { + if (parameters.type != Type.macOS && parameters.simulator) { + // if it is a simulator build then do not add the parameters below + return + } + + commandList.add("CODE_SIGN_IDENTITY=") + commandList.add("CODE_SIGNING_REQUIRED=NO") + //commandList.add("CODE_SIGN_ENTITLEMENTS=") + //commandList.add("CODE_SIGNING_ALLOWED=NO") + } + + private boolean isSimulator() { + isSimulatorBuildOf(Type.iOS) || isSimulatorBuildOf(Type.tvOS) + } + + def addBuildPath(ArrayList commandList) { + if (parameters.scheme) { + // add this parameter only if a scheme is set + commandList.add("-derivedDataPath") + commandList.add(parameters.derivedDataPath.absolutePath) + } + commandList.add("DSTROOT=" + parameters.dstRoot.absolutePath) + commandList.add("OBJROOT=" + parameters.objRoot.absolutePath) + commandList.add("SYMROOT=" + parameters.symRoot.absolutePath) + commandList.add("SHARED_PRECOMPS_DIR=" + parameters.sharedPrecompsDir.absolutePath) + } + + def addAdditionalParameters(ArrayList commandList) { + if (parameters.arch != null) { + StringBuilder archs = new StringBuilder("ARCHS="); + for (String singleArch in parameters.arch) { + if (archs.length() > 7) { + archs.append(" "); + } + archs.append(singleArch); + } + commandList.add(archs.toString()); + } + + if (parameters.additionalParameters instanceof List) { + for (String value in parameters.additionalParameters) { + commandList.add(value) + } + } else { + if (parameters.additionalParameters != null) { + commandList.add(parameters.additionalParameters) + } + } + } + + + def addDestinationSettingsForBuild(ArrayList commandList) { + if (isSimulator()) { + Destination destination = this.destinations.last() + commandList.add("-destination") + commandList.add(getDestinationCommandParameter(destination)) + } + if (parameters.type == Type.macOS) { + commandList.add("-destination") + commandList.add("platform=OS X,arch=x86_64") + } + } + + def addDestinationSettingsForTest(ArrayList commandList) { + switch (parameters.type) { + case Type.iOS: + case Type.tvOS: + this.destinations.each { destination -> + commandList.add("-destination") + commandList.add(getDestinationCommandParameter(destination)) + } + break; + + case Type.macOS: + commandList.add("-destination") + commandList.add("platform=OS X,arch=x86_64") + break; + + default: + break; + } + } + + void addCoverageSettings(ArrayList commandList) { + if (xcode.version.major < 7) { + commandList.add("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES") + commandList.add("GCC_GENERATE_TEST_COVERAGE_FILES=YES") + } else { + commandList.add("-enableCodeCoverage") + commandList.add("yes") + } + } + + + boolean isSimulatorBuildOf(Type expectedType) { + if (parameters.type != expectedType) { + return false + } + if (parameters.type != Type.macOS) { + // os x does not have a simulator + return parameters.simulator + } + return false + } + + protected String getDestinationCommandParameter(Destination destination) { + def destinationParameters = [] + + if (destination.platform != null) { + destinationParameters << "platform=" + destination.platform + } + if (destination.id != null) { + destinationParameters << "id=" + destination.id + } else { + if (destination.name != null) { + destinationParameters << "name=" + destination.name + } + /* + if (destination.arch != null && parameters.availableDestinations.platform.equals("OS X")) { + destinationParameters << "arch=" + destination.arch + } + + if (destination.os != null && parameters.availableDestinations.platform.equals("iOS Simulator")) { + destinationParameters << "OS=" + destination.os + } + */ + } + return destinationParameters.join(",") + } + + + String getToolchainDirectory() { + String buildSetting = getBuildSetting("TOOLCHAIN_DIR") + if (buildSetting != null) { + return buildSetting + } + return "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain" + } + + String getPlatformDirectory() { + return getBuildSetting("PLATFORM_DIR") + } + + String loadBuildSettings() { + def commandList = [xcode.xcodebuild, "clean", "-showBuildSettings"] + + if (parameters.scheme != null && parameters.workspace != null) { + commandList.add("-scheme"); + commandList.add(parameters.scheme) + commandList.add("-workspace") + commandList.add(parameters.workspace) + } + + return commandRunner.runWithResult(this.projectDirectory.absolutePath, commandList) + } + + private String getBuildSetting(String key) { + if (buildSettings == null) { + buildSettings = new HashMap<>() + String[] buildSettingsData = loadBuildSettings().split("\n") + for (line in buildSettingsData) { + int index = line.indexOf("=") + if (index > 0) { + String settingsKey = line.substring(0, index).trim() + String settingsValue = line.substring(index + 1, line.length()).trim() + buildSettings.put(settingsKey, settingsValue) + } + } + } + return buildSettings.get(key) + } + + @Override + public String toString() { + return "Xcodebuild{" + + "xcodePath='" + xcodePath + '\'' + + parameters + + '}' + } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 50d9d9bd..cef408a0 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -50,8 +50,102 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { return archiveDirectory } + @TaskAction + def archive() { +// if (project.xcodebuild.useXcodebuildArchive) { +// + File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + commandRunner.setOutputFile(outputFile) + + commandRunner.run("xcodebuild", + "archive", + "-scheme", + project.xcodebuild.scheme, + "-archivePath", + new File(project.buildDir, "archive/" + project.xcodebuild.scheme + ".xcarchive").absolutePath, + "-xcconfig", "test.xcconfig") + +// xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), +// project.xcodebuild.environment, +// getArchiveDirectory().absolutePath) + +// return +//// } + +// parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) +//// if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { +//// logger.debug("Create zip archive") +//// +//// // create zip archive +//// String zipFileName = parameters.bundleName +//// if (project.xcodebuild.bundleNameSuffix != null) { +//// zipFileName += project.xcodebuild.bundleNameSuffix +//// } +//// zipFileName += ".zip" +//// +//// def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) +//// def baseDirectory = parameters.applicationBundle.parentFile +//// +//// createZip(zipFile, baseDirectory, parameters.applicationBundle) +//// return +//// } +// +// logger.debug("Create xcarchive") +// Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) +// +//// if (project.xcodebuild.useXcodebuildArchive) { +// +// File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") +// commandRunner.setOutputFile(outputFile) +// +// xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) +// +// return +//// } +// +// // create xcarchive +// // copy application bundle +// copy(parameters.applicationBundle, getApplicationsDirectory()) +// +// File onDemandResources = new File(parameters.outputPath, "OnDemandResources") +// if (onDemandResources.exists()) { +// copy(onDemandResources, getProductsDirectory()) +// } +// +// // copy onDemandResources +// +// def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") +// dSymDirectory.mkdirs() +// copyDsyms(parameters.outputPath, dSymDirectory) +// +// List appBundles = getAppBundles(parameters.outputPath) +// for (File bundle : appBundles) { +// createEntitlements(bundle) +// createExtensionSupportDirectory(bundle, xcodebuild) +// } +// +// File applicationsDirectory = getApplicationsDirectory() +// +// File archiveDirectory = getArchiveDirectory() +// createInfoPlist(archiveDirectory) +// createFrameworks(archiveDirectory, xcodebuild) +// deleteEmptyFrameworks(archiveDirectory) +// deleteXCTestIfExists(applicationsDirectory) +// deleteFrameworksInExtension(applicationsDirectory) +// copyBCSymbolMaps(archiveDirectory) +// +// if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { +// File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) +// convertInfoPlistToBinary(applicationFolder) +// +// removeUnneededDylibsFromBundle(applicationFolder) +// } +// +// logger.debug("create archive done") + } + - private ArrayList getiOSIcons() { + ArrayList getiOSIcons() { return parameters.applicationBundle .list() .findAll { it.matches(ICON_FILE_MATCHER) } @@ -337,79 +431,6 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { } } - @TaskAction - def archive() { - parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) - if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { - logger.debug("Create zip archive") - - // create zip archive - String zipFileName = parameters.bundleName - if (project.xcodebuild.bundleNameSuffix != null) { - zipFileName += project.xcodebuild.bundleNameSuffix - } - zipFileName += ".zip" - - def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) - def baseDirectory = parameters.applicationBundle.parentFile - - createZip(zipFile, baseDirectory, parameters.applicationBundle) - return - } - - logger.debug("Create xcarchive") - Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) - - if (project.xcodebuild.useXcodebuildArchive) { - - File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - commandRunner.setOutputFile(outputFile) - - xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) - - return - } - - // create xcarchive - // copy application bundle - copy(parameters.applicationBundle, getApplicationsDirectory()) - - File onDemandResources = new File(parameters.outputPath, "OnDemandResources") - if (onDemandResources.exists()) { - copy(onDemandResources, getProductsDirectory()) - } - - // copy onDemandResources - - def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") - dSymDirectory.mkdirs() - copyDsyms(parameters.outputPath, dSymDirectory) - - List appBundles = getAppBundles(parameters.outputPath) - for (File bundle : appBundles) { - createEntitlements(bundle) - createExtensionSupportDirectory(bundle, xcodebuild) - } - - File applicationsDirectory = getApplicationsDirectory() - - File archiveDirectory = getArchiveDirectory() - createInfoPlist(archiveDirectory) - createFrameworks(archiveDirectory, xcodebuild) - deleteEmptyFrameworks(archiveDirectory) - deleteXCTestIfExists(applicationsDirectory) - deleteFrameworksInExtension(applicationsDirectory) - copyBCSymbolMaps(archiveDirectory) - - if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { - File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) - convertInfoPlistToBinary(applicationFolder) - - removeUnneededDylibsFromBundle(applicationFolder) - } - - logger.debug("create archive done") - } def copyBCSymbolMaps(File archiveDirectory) { if (!parameters.bitcode) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy new file mode 100644 index 00000000..fd545346 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -0,0 +1,95 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openbakery + +import org.gradle.api.tasks.* +import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.xcode.Xcodebuild + +//@CompileStatic +class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { + + public static final String FOLDER_ARCHIVE = "archive" + public static final String FOLDER_XCCONFIG = "xcconfig" + + XcodeBuildArchiveTaskIosAndTvOS() { + super() + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + + this.description = "Prepare the app bundle that it can be archive" + } + + @Input + String getScheme() { + return project.xcodebuild.scheme + } + + @InputFile + @Optional + File getProvisioningFile() { + return project.xcodebuild.signing.mobileProvisionFile.first() + } + + @OutputFile + File getOutputTextFile() { + File file = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + return file + } + + @OutputDirectory + File getOutputDirectory() { + def archiveDirectory = new File(project.getBuildDir(), FOLDER_ARCHIVE + + "/" + project.xcodebuild.scheme + ".xcarchive") + archiveDirectory.mkdirs() + return archiveDirectory + } + + @OutputFile + File getXcconfigFile() { + return new File(getOutputDirectory(), "project.xcconfig") + } + + @TaskAction + private void archive() { + generateXConfigFile() + runArchiving() + } + + private void generateXConfigFile() { + File file = getProvisioningFile() + if (file.exists()) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(file, commandRunner) + println reader.getTeamIdentifierPrefix() + println reader.getUUID() + } + } + + private void runArchiving() { + Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, + commandRunner, + xcode, + parameters, + getDestinations()) + + commandRunner.setOutputFile(getOutputTextFile()) + + xcodebuild.archive(getScheme(), + getOutputDirectory(), + project.file("test.xcconfig")) + } +} diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 4a8185c7..220af21e 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -67,473 +67,479 @@ import org.openbakery.simulators.SimulatorsListTask import org.openbakery.simulators.SimulatorStartTask import org.openbakery.simulators.SimulatorRunAppTask import org.openbakery.simulators.SimulatorInstallAppTask +import org.openbakery.xcode.Type import org.slf4j.Logger import org.slf4j.LoggerFactory class XcodePlugin implements Plugin { - private static Logger logger = LoggerFactory.getLogger(XcodePlugin.class) - - public static final String XCODE_GROUP_NAME = "Xcode" - public static final String HOCKEYKIT_GROUP_NAME = "HockeyKit" - public static final String HOCKEYAPP_GROUP_NAME = "HockeyApp" - public static final String APPSTORE_GROUP_NAME = "AppStore" - public static final String DEPLOYGATE_GROUP_NAME = "DeployGate" - public static final String CRASHLYTICS_GROUP_NAME = "Crashlytics" - public static final String APPLE_DOC_GROUP_NAME = "Appledoc" - public static final String COVERAGE_GROUP_NAME = "Coverage" - public static final String COCOAPODS_GROUP_NAME = "Cocoapods" - public static final String CARTHAGE_GROUP_NAME = "Carthage" - public static final String SIMULATORS_GROUP_NAME = "Simulators" - public static final String ANALYTICS_GROUP_NAME = "Analytics" - - - public static final String XCODE_TEST_TASK_NAME = "xcodetest" - public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" - public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" - public static final String ARCHIVE_TASK_NAME = "archive" - public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" - public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" - public static final String SIMULATORS_CLEAN_TASK_NAME = "simulatorsClean" - public static final String SIMULATORS_START_TASK_NAME = "simulatorStart" - public static final String SIMULATORS_INSTALL_APP_TASK_NAME = "simulatorInstallApp" - public static final String SIMULATORS_RUN_APP_TASK_NAME = "simulatorRunApp" - public static final String SIMULATORS_KILL_TASK_NAME = "simulatorKill" - public static final String XCODE_BUILD_TASK_NAME = "xcodebuild" - public static final String XCODE_CLEAN_TASK_NAME = "xcodebuildClean" - public static final String XCODE_CONFIG_TASK_NAME = "xcodebuildConfig" - public static final String HOCKEYKIT_MANIFEST_TASK_NAME = "hockeykitManifest" - public static final String HOCKEYKIT_ARCHIVE_TASK_NAME = "hockeykitArchive" - public static final String HOCKEYKIT_NOTES_TASK_NAME = "hockeykitNotes" - public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" - public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" - public static final String HOCKEYKIT_TASK_NAME = "hockeykit" - public static final String KEYCHAIN_CREATE_TASK_NAME = "keychainCreate" - public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" - public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" - public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' - public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' - public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' - public static final String PACKAGE_TASK_NAME = 'package' - public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' - public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' - public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' - public static final String HOCKEYAPP_CLEAN_TASK_NAME = 'hockeyappClean' - public static final String HOCKEYAPP_TASK_NAME = 'hockeyapp' - public static final String DEPLOYGATE_TASK_NAME = 'deploygate' - public static final String DEPLOYGATE_CLEAN_TASK_NAME = 'deploygateClean' - public static final String CRASHLYTICS_TASK_NAME = 'crashlytics' - public static final String COCOAPODS_INSTALL_TASK_NAME = 'cocoapodsInstall' - public static final String COCOAPODS_UPDATE_TASK_NAME = 'cocoapodsUpdate' - public static final String COCOAPODS_BOOTSTRAP_TASK_NAME = 'cocoapodsBootstrap' - public static final String OCLINT_TASK_NAME = 'oclint' - public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' - public static final String CPD_TASK_NAME = 'cpd' - public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' - public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' - - - public static final String APPLEDOC_TASK_NAME = 'appledoc' - public static final String APPLEDOC_CLEAN_TASK_NAME = 'appledocClean' - - public static final COVERAGE_TASK_NAME = 'coverage' - public static final COVERAGE_CLEAN_TASK_NAME = 'coverageClean' - - - public static final String SDK_IPHONESIMULATOR = "iphonesimulator" - - - - - void apply(Project project) { - project.getPlugins().apply(BasePlugin.class); - - System.setProperty("java.awt.headless", "true"); - - configureExtensions(project) - configureClean(project) - configureBuild(project) - configureTest(project) - configureArchive(project) - configureHockeyKit(project) - configureKeychain(project) - configureInfoPlist(project) - configureProvisioning(project) - configureAppstore(project) - configureHockeyApp(project) - configureDeployGate(project) - configureCrashlytics(project) - configurePackage(project) - configureAppledoc(project) - configureCoverage(project) - configureCpd(project) - configureCocoapods(project) - configureCarthage(project) - configureOCLint(project) - configureSimulatorTasks(project) - configureProperties(project) - } - - - void configureProperties(Project project) { - - project.afterEvaluate { - - if (project.hasProperty('infoplist.bundleIdentifier')) { - project.infoplist.bundleIdentifier = project['infoplist.bundleIdentifier'] - } - if (project.hasProperty('infoplist.bundleIdentifierSuffix')) { - project.infoplist.bundleIdentifierSuffix = project['infoplist.bundleIdentifierSuffix'] - } - if (project.hasProperty('infoplist.bundleDisplayName')) { - project.infoplist.bundleDisplayName = project['infoplist.bundleDisplayName'] - } - if (project.hasProperty('infoplist.bundleDisplayNameSuffix')) { - project.infoplist.bundleDisplayNameSuffix = project['infoplist.bundleDisplayNameSuffix'] - } - - if (project.hasProperty('infoplist.version')) { - project.infoplist.version = project['infoplist.version'] - } - if (project.hasProperty('infoplist.versionPrefix')) { - project.infoplist.versionPrefix = project['infoplist.versionPrefix'] - } - if (project.hasProperty('infoplist.versionSuffix')) { - project.infoplist.versionSuffix = project['infoplist.versionSuffix'] - } - - - if (project.hasProperty('infoplist.shortVersionString')) { - project.infoplist.shortVersionString = project['infoplist.shortVersionString'] - } - if (project.hasProperty('infoplist.shortVersionStringSuffix')) { - project.infoplist.shortVersionStringSuffix = project['infoplist.shortVersionStringSuffix'] - } - if (project.hasProperty('infoplist.shortVersionStringPrefix')) { - project.infoplist.shortVersionStringPrefix = project['infoplist.shortVersionStringPrefix'] - } - - if (project.hasProperty('infoplist.iconPath')) { - project.infoplist.iconPath = project['infoplist.iconPath'] - } - - if (project.hasProperty('xcodebuild.scheme')) { - project.xcodebuild.scheme = project['xcodebuild.scheme'] - } - if (project.hasProperty('xcodebuild.infoPlist')) { - project.xcodebuild.infoPlist = project['xcodebuild.infoPlist'] - } - if (project.hasProperty('xcodebuild.configuration')) { - project.xcodebuild.configuration = project['xcodebuild.configuration'] - } - if (project.hasProperty('xcodebuild.sdk')) { - project.xcodebuild.sdk = project['xcodebuild.sdk'] - } - if (project.hasProperty('xcodebuild.target')) { - project.xcodebuild.target = project['xcodebuild.target'] - } - if (project.hasProperty('xcodebuild.dstRoot')) { - project.xcodebuild.dstRoot = project['xcodebuild.dstRoot'] - } - if (project.hasProperty('xcodebuild.objRoot')) { - project.xcodebuild.objRoot = project['xcodebuild.objRoot'] - } - if (project.hasProperty('xcodebuild.symRoot')) { - project.xcodebuild.symRoot = project['xcodebuild.symRoot'] - } - if (project.hasProperty('xcodebuild.sharedPrecompsDir')) { - project.xcodebuild.sharedPrecompsDir = project['xcodebuild.sharedPrecompsDir'] - } - if (project.hasProperty('xcodebuild.sourceDirectory')) { - project.xcodebuild.sourceDirectory = project['xcodebuild.sourceDirectory'] - } - - if (project.hasProperty('xcodebuild.signing.identity')) { - project.xcodebuild.signing.identity = project['xcodebuild.signing.identity'] - } - if (project.hasProperty('xcodebuild.signing.certificateURI')) { - project.xcodebuild.signing.certificateURI = project['xcodebuild.signing.certificateURI'] - } - if (project.hasProperty('xcodebuild.signing.certificatePassword')) { - project.xcodebuild.signing.certificatePassword = project['xcodebuild.signing.certificatePassword'] - } - if (project.hasProperty('xcodebuild.signing.mobileProvisionURI')) { - project.xcodebuild.signing.mobileProvisionURI = project['xcodebuild.signing.mobileProvisionURI'] - } - if (project.hasProperty('xcodebuild.signing.keychain')) { - project.xcodebuild.signing.keychain = project['xcodebuild.signing.keychain'] - } - if (project.hasProperty('xcodebuild.signing.keychainPassword')) { - project.xcodebuild.signing.keychainPassword = project['signing.keychainPassword'] - } - if (project.hasProperty('xcodebuild.signing.timeout')) { - project.xcodebuild.signing.timeout = project['signing.timeout'] - } - - if (project.hasProperty('xcodebuild.additionalParameters')) { - project.xcodebuild.additionalParameters = project['xcodebuild.additionalParameters'] - } - if (project.hasProperty('xcodebuild.bundleNameSuffix')) { - project.xcodebuild.bundleNameSuffix = project['xcodebuild.bundleNameSuffix'] - } - if (project.hasProperty('xcodebuild.arch')) { - project.xcodebuild.arch = project['xcodebuild.arch'] - } - if (project.hasProperty('xcodebuild.environment')) { - project.xcodebuild.environment = project['xcodebuild.environment'] - } - if (project.hasProperty('xcodebuild.version')) { - project.xcodebuild.version = project['xcodebuild.version'] - } - if (project.hasProperty('xcodebuild.ipaFileName')) { - project.xcodebuild.ipaFileName = project['xcodebuild.ipaFileName'] - } - if (project.hasProperty('xcodebuild.destination')) { - project.xcodebuild.destination = project['xcodebuild.destination'] - } - - if (project.hasProperty('hockeykit.displayName')) { - project.hockeykit.displayName = project['hockeykit.displayName'] - } - if (project.hasProperty('hockeykit.versionDirectoryName')) { - project.hockeykit.versionDirectoryName = project['hockeykit.versionDirectoryName'] - } - if (project.hasProperty('hockeykit.outputDirectory')) { - project.hockeykit.outputDirectory = project['hockeykit.outputDirectory'] - } - if (project.hasProperty('hockeykit.notes')) { - project.hockeykit.notes = project['hockeykit.notes'] - } - - - if (project.hasProperty('hockeyapp.apiToken')) { - project.hockeyapp.apiToken = project['hockeyapp.apiToken'] - } - if (project.hasProperty('hockeyapp.appID')) { - project.hockeyapp.appID = project['hockeyapp.appID'] - } - if (project.hasProperty('hockeyapp.notes')) { - project.hockeyapp.notes = project['hockeyapp.notes'] - } - if (project.hasProperty('hockeyapp.status')) { - project.hockeyapp.status = project['hockeyapp.status'] - } - if (project.hasProperty('hockeyapp.notify')) { - project.hockeyapp.notify = project['hockeyapp.notify'] - } - if (project.hasProperty('hockeyapp.notesType')) { - project.hockeyapp.notesType = project['hockeyapp.notesType'] - } - if (project.hasProperty('hockeyapp.teams')) { - project.hockeyapp.teams = project['hockeyapp.teams'] - } - if (project.hasProperty('hockeyapp.tags')) { - project.hockeyapp.tags = project['hockeyapp.tags'] - } - if (project.hasProperty('hockeyapp.releaseType')) { - project.hockeyapp.releaseType = project['hockeyapp.releaseType'] - } - if (project.hasProperty('hockeyapp.privatePage')) { - project.hockeyapp.privatePage = project['hockeyapp.privatePage'] - } - if (project.hasProperty('hockeyapp.commitSha')) { - project.hockeyapp.commitSha = project['hockeyapp.commitSha'] - } - if (project.hasProperty('hockeyapp.buildServerUrl')) { - project.hockeyapp.buildServerUrl = project['hockeyapp.buildServerUrl'] - } - if (project.hasProperty('hockeyapp.repositoryUrl')) { - project.hockeyapp.repositoryUrl = project['hockeyapp.repositoryUrl'] - } - - if (project.hasProperty('deploygate.outputDirectory')) { - project.deploygate.outputDirectory = project['deploygate.outputDirectory'] - } - - if (project.hasProperty('deploygate.apiToken')) { - project.deploygate.apiToken = project['deploygate.apiToken'] - } - if (project.hasProperty('deploygate.userName')) { - project.deploygate.userName = project['deploygate.userName'] - } - if (project.hasProperty('deploygate.message')) { - project.deploygate.message = project['deploygate.message'] - } - - if (project.hasProperty('crashlytics.submitCommand')) { - project.crashlytics.submitCommand = project['crashlytics.submitCommand'] - } - if (project.hasProperty('crashlytics.apiKey')) { - project.crashlytics.apiKey = project['crashlytics.apiKey'] - } - if (project.hasProperty('crashlytics.buildSecret')) { - project.crashlytics.buildSecret = project['crashlytics.buildSecret'] - } - if (project.hasProperty('crashlytics.emails')) { - project.crashlytics.emails = project['crashlytics.emails'] - } - if (project.hasProperty('crashlytics.groupAliases')) { - project.crashlytics.groupAliases = project['crashlytics.groupAliases'] - } - if (project.hasProperty('crashlytics.notesPath')) { - project.crashlytics.notesPath = project['crashlytics.notesPath'] - } - if (project.hasProperty('crashlytics.notifications')) { - project.crashlytics.notifications = project['crashlytics.notifications'] - } - - if (project.hasProperty('coverage.outputFormat')) { - project.coverage.outputFormat = project['coverage.outputFormat'] - } - if (project.hasProperty('coverage.exclude')) { - project.coverage.exclude = project['coverage.exclude'] - } - - if (project.hasProperty('appstore.username')) { - project.appstore.username = project['appstore.username'] - } - if (project.hasProperty('appstore.password')) { - project.appstore.password = project['appstore.password'] - } - - - if (project.hasProperty('oclint.reportType')) { - project.oclint.reportType = project['oclint.reportType']; - } - if (project.hasProperty('oclint.rules')) { - project.oclint.rules = project['oclint.rules']; - } - if (project.hasProperty('oclint.disableRules')) { - project.oclint.disableRules = project['oclint.disableRules']; - } - if (project.hasProperty('oclint.excludes')) { - project.oclint.excludes = project['oclint.excludes']; - } - if (project.hasProperty('oclint.maxPriority1')) { - project.oclint.maxPriority1 = project['oclint.maxPriority1']; - } - if (project.hasProperty('oclint.maxPriority2')) { - project.oclint.maxPriority2 = project['oclint.maxPriority2']; - } - if (project.hasProperty('oclint.maxPriority3')) { - project.oclint.maxPriority3 = project['oclint.maxPriority3']; - } - - - Task testTask = (Test) project.getTasks().findByPath(JavaPlugin.TEST_TASK_NAME) - if (testTask == null) { - testTask = project.getTasks().create(JavaPlugin.TEST_TASK_NAME) - } - testTask.dependsOn(XCODE_TEST_TASK_NAME) - - - configureCarthageDependencies(project) - configureCocoapodsDependencies(project) - configureTestRunDependencies(project) - } - - } - - - void configureExtensions(Project project) { - project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) - project.extensions.create("infoplist", InfoPlistExtension) - project.extensions.create("hockeykit", HockeyKitPluginExtension, project) - project.extensions.create("appstore", AppstorePluginExtension, project) - project.extensions.create("hockeyapp", HockeyAppPluginExtension, project) - project.extensions.create("deploygate", DeployGatePluginExtension, project) - project.extensions.create("crashlytics", CrashlyticsPluginExtension, project) - project.extensions.create("coverage", CoveragePluginExtension, project) - project.extensions.create("oclint", OCLintPluginExtension, project) - } - - - private void configureTestRunDependencies(Project project) { - for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { - if (xcodeTestRunTask.runOnDevice()) { - xcodeTestRunTask.dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - } - } - } - - private void configureBuild(Project project) { - XcodeBuildTask xcodebuildTask = project.getTasks().create(XCODE_BUILD_TASK_NAME, XcodeBuildTask.class); - xcodebuildTask.setGroup(XCODE_GROUP_NAME); - - XcodeConfigTask configTask = project.getTasks().create(XCODE_CONFIG_TASK_NAME, XcodeConfigTask.class); - configTask.setGroup(XCODE_GROUP_NAME); - - project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(xcodebuildTask); - } - - - private void configureClean(Project project) { - XcodeBuildCleanTask xcodeBuildCleanTask = project.getTasks().create(XCODE_CLEAN_TASK_NAME, XcodeBuildCleanTask.class); - xcodeBuildCleanTask.setGroup(XCODE_GROUP_NAME); - - project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(xcodeBuildCleanTask); - } - - private void configureArchive(Project project) { - XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); - xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); - - //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); - } - - private void configureSimulatorTasks(Project project) { - project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_START_TASK_NAME, type: SimulatorStartTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_RUN_APP_TASK_NAME, type: SimulatorRunAppTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_INSTALL_APP_TASK_NAME, type: SimulatorInstallAppTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_KILL_TASK_NAME, type: SimulatorKillTask, group: SIMULATORS_LIST_TASK_NAME) - } + private static Logger logger = LoggerFactory.getLogger(XcodePlugin.class) + + public static final String XCODE_GROUP_NAME = "Xcode" + public static final String HOCKEYKIT_GROUP_NAME = "HockeyKit" + public static final String HOCKEYAPP_GROUP_NAME = "HockeyApp" + public static final String APPSTORE_GROUP_NAME = "AppStore" + public static final String DEPLOYGATE_GROUP_NAME = "DeployGate" + public static final String CRASHLYTICS_GROUP_NAME = "Crashlytics" + public static final String APPLE_DOC_GROUP_NAME = "Appledoc" + public static final String COVERAGE_GROUP_NAME = "Coverage" + public static final String COCOAPODS_GROUP_NAME = "Cocoapods" + public static final String CARTHAGE_GROUP_NAME = "Carthage" + public static final String SIMULATORS_GROUP_NAME = "Simulators" + public static final String ANALYTICS_GROUP_NAME = "Analytics" + + + public static final String XCODE_TEST_TASK_NAME = "xcodetest" + public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" + public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" + public static final String ARCHIVE_TASK_NAME = "archive" + public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" + public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" + public static final String SIMULATORS_CLEAN_TASK_NAME = "simulatorsClean" + public static final String SIMULATORS_START_TASK_NAME = "simulatorStart" + public static final String SIMULATORS_INSTALL_APP_TASK_NAME = "simulatorInstallApp" + public static final String SIMULATORS_RUN_APP_TASK_NAME = "simulatorRunApp" + public static final String SIMULATORS_KILL_TASK_NAME = "simulatorKill" + public static final String XCODE_BUILD_TASK_NAME = "xcodebuild" + public static final String XCODE_CLEAN_TASK_NAME = "xcodebuildClean" + public static final String XCODE_CONFIG_TASK_NAME = "xcodebuildConfig" + public static final String HOCKEYKIT_MANIFEST_TASK_NAME = "hockeykitManifest" + public static final String HOCKEYKIT_ARCHIVE_TASK_NAME = "hockeykitArchive" + public static final String HOCKEYKIT_NOTES_TASK_NAME = "hockeykitNotes" + public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" + public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" + public static final String HOCKEYKIT_TASK_NAME = "hockeykit" + public static final String KEYCHAIN_CREATE_TASK_NAME = "keychainCreate" + public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" + public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" + public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' + public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' + public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' + public static final String PACKAGE_TASK_NAME = 'package' + public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' + public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' + public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' + public static final String HOCKEYAPP_CLEAN_TASK_NAME = 'hockeyappClean' + public static final String HOCKEYAPP_TASK_NAME = 'hockeyapp' + public static final String DEPLOYGATE_TASK_NAME = 'deploygate' + public static final String DEPLOYGATE_CLEAN_TASK_NAME = 'deploygateClean' + public static final String CRASHLYTICS_TASK_NAME = 'crashlytics' + public static final String COCOAPODS_INSTALL_TASK_NAME = 'cocoapodsInstall' + public static final String COCOAPODS_UPDATE_TASK_NAME = 'cocoapodsUpdate' + public static final String COCOAPODS_BOOTSTRAP_TASK_NAME = 'cocoapodsBootstrap' + public static final String OCLINT_TASK_NAME = 'oclint' + public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' + public static final String CPD_TASK_NAME = 'cpd' + public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' + public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' + + + public static final String APPLEDOC_TASK_NAME = 'appledoc' + public static final String APPLEDOC_CLEAN_TASK_NAME = 'appledocClean' + + public static final COVERAGE_TASK_NAME = 'coverage' + public static final COVERAGE_CLEAN_TASK_NAME = 'coverageClean' + + + public static final String SDK_IPHONESIMULATOR = "iphonesimulator" + + + void apply(Project project) { + project.getPlugins().apply(BasePlugin.class); + + System.setProperty("java.awt.headless", "true"); + + configureExtensions(project) + configureClean(project) + configureBuild(project) + configureTest(project) + configureArchive(project) + configureHockeyKit(project) + configureKeychain(project) + configureInfoPlist(project) + configureProvisioning(project) + configureAppstore(project) + configureHockeyApp(project) + configureDeployGate(project) + configureCrashlytics(project) + configurePackage(project) + configureAppledoc(project) + configureCoverage(project) + configureCpd(project) + configureCocoapods(project) + configureCarthage(project) + configureOCLint(project) + configureSimulatorTasks(project) + configureProperties(project) + } + + + void configureProperties(Project project) { + + project.afterEvaluate { + + if (project.hasProperty('infoplist.bundleIdentifier')) { + project.infoplist.bundleIdentifier = project['infoplist.bundleIdentifier'] + } + if (project.hasProperty('infoplist.bundleIdentifierSuffix')) { + project.infoplist.bundleIdentifierSuffix = project['infoplist.bundleIdentifierSuffix'] + } + if (project.hasProperty('infoplist.bundleDisplayName')) { + project.infoplist.bundleDisplayName = project['infoplist.bundleDisplayName'] + } + if (project.hasProperty('infoplist.bundleDisplayNameSuffix')) { + project.infoplist.bundleDisplayNameSuffix = project['infoplist.bundleDisplayNameSuffix'] + } + + if (project.hasProperty('infoplist.version')) { + project.infoplist.version = project['infoplist.version'] + } + if (project.hasProperty('infoplist.versionPrefix')) { + project.infoplist.versionPrefix = project['infoplist.versionPrefix'] + } + if (project.hasProperty('infoplist.versionSuffix')) { + project.infoplist.versionSuffix = project['infoplist.versionSuffix'] + } + + + if (project.hasProperty('infoplist.shortVersionString')) { + project.infoplist.shortVersionString = project['infoplist.shortVersionString'] + } + if (project.hasProperty('infoplist.shortVersionStringSuffix')) { + project.infoplist.shortVersionStringSuffix = project['infoplist.shortVersionStringSuffix'] + } + if (project.hasProperty('infoplist.shortVersionStringPrefix')) { + project.infoplist.shortVersionStringPrefix = project['infoplist.shortVersionStringPrefix'] + } + + if (project.hasProperty('infoplist.iconPath')) { + project.infoplist.iconPath = project['infoplist.iconPath'] + } + + if (project.hasProperty('xcodebuild.scheme')) { + project.xcodebuild.scheme = project['xcodebuild.scheme'] + } + if (project.hasProperty('xcodebuild.infoPlist')) { + project.xcodebuild.infoPlist = project['xcodebuild.infoPlist'] + } + if (project.hasProperty('xcodebuild.configuration')) { + project.xcodebuild.configuration = project['xcodebuild.configuration'] + } + if (project.hasProperty('xcodebuild.sdk')) { + project.xcodebuild.sdk = project['xcodebuild.sdk'] + } + if (project.hasProperty('xcodebuild.target')) { + project.xcodebuild.target = project['xcodebuild.target'] + } + if (project.hasProperty('xcodebuild.dstRoot')) { + project.xcodebuild.dstRoot = project['xcodebuild.dstRoot'] + } + if (project.hasProperty('xcodebuild.objRoot')) { + project.xcodebuild.objRoot = project['xcodebuild.objRoot'] + } + if (project.hasProperty('xcodebuild.symRoot')) { + project.xcodebuild.symRoot = project['xcodebuild.symRoot'] + } + if (project.hasProperty('xcodebuild.sharedPrecompsDir')) { + project.xcodebuild.sharedPrecompsDir = project['xcodebuild.sharedPrecompsDir'] + } + if (project.hasProperty('xcodebuild.sourceDirectory')) { + project.xcodebuild.sourceDirectory = project['xcodebuild.sourceDirectory'] + } + + if (project.hasProperty('xcodebuild.signing.identity')) { + project.xcodebuild.signing.identity = project['xcodebuild.signing.identity'] + } + if (project.hasProperty('xcodebuild.signing.certificateURI')) { + project.xcodebuild.signing.certificateURI = project['xcodebuild.signing.certificateURI'] + } + if (project.hasProperty('xcodebuild.signing.certificatePassword')) { + project.xcodebuild.signing.certificatePassword = project['xcodebuild.signing.certificatePassword'] + } + if (project.hasProperty('xcodebuild.signing.mobileProvisionURI')) { + project.xcodebuild.signing.mobileProvisionURI = project['xcodebuild.signing.mobileProvisionURI'] + } + if (project.hasProperty('xcodebuild.signing.keychain')) { + project.xcodebuild.signing.keychain = project['xcodebuild.signing.keychain'] + } + if (project.hasProperty('xcodebuild.signing.keychainPassword')) { + project.xcodebuild.signing.keychainPassword = project['signing.keychainPassword'] + } + if (project.hasProperty('xcodebuild.signing.timeout')) { + project.xcodebuild.signing.timeout = project['signing.timeout'] + } + + if (project.hasProperty('xcodebuild.additionalParameters')) { + project.xcodebuild.additionalParameters = project['xcodebuild.additionalParameters'] + } + if (project.hasProperty('xcodebuild.bundleNameSuffix')) { + project.xcodebuild.bundleNameSuffix = project['xcodebuild.bundleNameSuffix'] + } + if (project.hasProperty('xcodebuild.arch')) { + project.xcodebuild.arch = project['xcodebuild.arch'] + } + if (project.hasProperty('xcodebuild.environment')) { + project.xcodebuild.environment = project['xcodebuild.environment'] + } + if (project.hasProperty('xcodebuild.version')) { + project.xcodebuild.version = project['xcodebuild.version'] + } + if (project.hasProperty('xcodebuild.ipaFileName')) { + project.xcodebuild.ipaFileName = project['xcodebuild.ipaFileName'] + } + if (project.hasProperty('xcodebuild.destination')) { + project.xcodebuild.destination = project['xcodebuild.destination'] + } + + if (project.hasProperty('hockeykit.displayName')) { + project.hockeykit.displayName = project['hockeykit.displayName'] + } + if (project.hasProperty('hockeykit.versionDirectoryName')) { + project.hockeykit.versionDirectoryName = project['hockeykit.versionDirectoryName'] + } + if (project.hasProperty('hockeykit.outputDirectory')) { + project.hockeykit.outputDirectory = project['hockeykit.outputDirectory'] + } + if (project.hasProperty('hockeykit.notes')) { + project.hockeykit.notes = project['hockeykit.notes'] + } + + + if (project.hasProperty('hockeyapp.apiToken')) { + project.hockeyapp.apiToken = project['hockeyapp.apiToken'] + } + if (project.hasProperty('hockeyapp.appID')) { + project.hockeyapp.appID = project['hockeyapp.appID'] + } + if (project.hasProperty('hockeyapp.notes')) { + project.hockeyapp.notes = project['hockeyapp.notes'] + } + if (project.hasProperty('hockeyapp.status')) { + project.hockeyapp.status = project['hockeyapp.status'] + } + if (project.hasProperty('hockeyapp.notify')) { + project.hockeyapp.notify = project['hockeyapp.notify'] + } + if (project.hasProperty('hockeyapp.notesType')) { + project.hockeyapp.notesType = project['hockeyapp.notesType'] + } + if (project.hasProperty('hockeyapp.teams')) { + project.hockeyapp.teams = project['hockeyapp.teams'] + } + if (project.hasProperty('hockeyapp.tags')) { + project.hockeyapp.tags = project['hockeyapp.tags'] + } + if (project.hasProperty('hockeyapp.releaseType')) { + project.hockeyapp.releaseType = project['hockeyapp.releaseType'] + } + if (project.hasProperty('hockeyapp.privatePage')) { + project.hockeyapp.privatePage = project['hockeyapp.privatePage'] + } + if (project.hasProperty('hockeyapp.commitSha')) { + project.hockeyapp.commitSha = project['hockeyapp.commitSha'] + } + if (project.hasProperty('hockeyapp.buildServerUrl')) { + project.hockeyapp.buildServerUrl = project['hockeyapp.buildServerUrl'] + } + if (project.hasProperty('hockeyapp.repositoryUrl')) { + project.hockeyapp.repositoryUrl = project['hockeyapp.repositoryUrl'] + } + + if (project.hasProperty('deploygate.outputDirectory')) { + project.deploygate.outputDirectory = project['deploygate.outputDirectory'] + } + + if (project.hasProperty('deploygate.apiToken')) { + project.deploygate.apiToken = project['deploygate.apiToken'] + } + if (project.hasProperty('deploygate.userName')) { + project.deploygate.userName = project['deploygate.userName'] + } + if (project.hasProperty('deploygate.message')) { + project.deploygate.message = project['deploygate.message'] + } + + if (project.hasProperty('crashlytics.submitCommand')) { + project.crashlytics.submitCommand = project['crashlytics.submitCommand'] + } + if (project.hasProperty('crashlytics.apiKey')) { + project.crashlytics.apiKey = project['crashlytics.apiKey'] + } + if (project.hasProperty('crashlytics.buildSecret')) { + project.crashlytics.buildSecret = project['crashlytics.buildSecret'] + } + if (project.hasProperty('crashlytics.emails')) { + project.crashlytics.emails = project['crashlytics.emails'] + } + if (project.hasProperty('crashlytics.groupAliases')) { + project.crashlytics.groupAliases = project['crashlytics.groupAliases'] + } + if (project.hasProperty('crashlytics.notesPath')) { + project.crashlytics.notesPath = project['crashlytics.notesPath'] + } + if (project.hasProperty('crashlytics.notifications')) { + project.crashlytics.notifications = project['crashlytics.notifications'] + } + + if (project.hasProperty('coverage.outputFormat')) { + project.coverage.outputFormat = project['coverage.outputFormat'] + } + if (project.hasProperty('coverage.exclude')) { + project.coverage.exclude = project['coverage.exclude'] + } + + if (project.hasProperty('appstore.username')) { + project.appstore.username = project['appstore.username'] + } + if (project.hasProperty('appstore.password')) { + project.appstore.password = project['appstore.password'] + } + + + if (project.hasProperty('oclint.reportType')) { + project.oclint.reportType = project['oclint.reportType']; + } + if (project.hasProperty('oclint.rules')) { + project.oclint.rules = project['oclint.rules']; + } + if (project.hasProperty('oclint.disableRules')) { + project.oclint.disableRules = project['oclint.disableRules']; + } + if (project.hasProperty('oclint.excludes')) { + project.oclint.excludes = project['oclint.excludes']; + } + if (project.hasProperty('oclint.maxPriority1')) { + project.oclint.maxPriority1 = project['oclint.maxPriority1']; + } + if (project.hasProperty('oclint.maxPriority2')) { + project.oclint.maxPriority2 = project['oclint.maxPriority2']; + } + if (project.hasProperty('oclint.maxPriority3')) { + project.oclint.maxPriority3 = project['oclint.maxPriority3']; + } + + + Task testTask = (Test) project.getTasks().findByPath(JavaPlugin.TEST_TASK_NAME) + if (testTask == null) { + testTask = project.getTasks().create(JavaPlugin.TEST_TASK_NAME) + } + testTask.dependsOn(XCODE_TEST_TASK_NAME) + + + configureCarthageDependencies(project) + configureCocoapodsDependencies(project) + configureTestRunDependencies(project) + } + + } + + + void configureExtensions(Project project) { + project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) + project.extensions.create("infoplist", InfoPlistExtension) + project.extensions.create("hockeykit", HockeyKitPluginExtension, project) + project.extensions.create("appstore", AppstorePluginExtension, project) + project.extensions.create("hockeyapp", HockeyAppPluginExtension, project) + project.extensions.create("deploygate", DeployGatePluginExtension, project) + project.extensions.create("crashlytics", CrashlyticsPluginExtension, project) + project.extensions.create("coverage", CoveragePluginExtension, project) + project.extensions.create("oclint", OCLintPluginExtension, project) + } + + + private void configureTestRunDependencies(Project project) { + for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { + if (xcodeTestRunTask.runOnDevice()) { + xcodeTestRunTask.dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) + } + } + } + + private void configureBuild(Project project) { + XcodeBuildTask xcodebuildTask = project.getTasks().create(XCODE_BUILD_TASK_NAME, XcodeBuildTask.class); + xcodebuildTask.setGroup(XCODE_GROUP_NAME); + + XcodeConfigTask configTask = project.getTasks().create(XCODE_CONFIG_TASK_NAME, XcodeConfigTask.class); + configTask.setGroup(XCODE_GROUP_NAME); + + project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(xcodebuildTask); + } + + + private void configureClean(Project project) { + XcodeBuildCleanTask xcodeBuildCleanTask = project.getTasks().create(XCODE_CLEAN_TASK_NAME, XcodeBuildCleanTask.class); + xcodeBuildCleanTask.setGroup(XCODE_GROUP_NAME); + + project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(xcodeBuildCleanTask); + } + + private void configureArchive(Project project) { + if (project.xcodebuild.type == Type.tvOS + || project.xcodebuild.type == Type.iOS) { + XcodeBuildArchiveTaskIosAndTvOS task = project.tasks.create(ARCHIVE_TASK_NAME, + XcodeBuildArchiveTaskIosAndTvOS.class) + task.setGroup(XCODE_GROUP_NAME) + } else { + XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); + xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); + } + + //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); + } + + private void configureSimulatorTasks(Project project) { + project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_START_TASK_NAME, type: SimulatorStartTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_RUN_APP_TASK_NAME, type: SimulatorRunAppTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_INSTALL_APP_TASK_NAME, type: SimulatorInstallAppTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_KILL_TASK_NAME, type: SimulatorKillTask, group: SIMULATORS_LIST_TASK_NAME) + } + + private void configureHockeyKit(Project project) { + project.task(HOCKEYKIT_MANIFEST_TASK_NAME, type: HockeyKitManifestTask, group: HOCKEYKIT_GROUP_NAME) + HockeyKitArchiveTask hockeyKitArchiveTask = project.task(HOCKEYKIT_ARCHIVE_TASK_NAME, type: HockeyKitArchiveTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_NOTES_TASK_NAME, type: HockeyKitReleaseNotesTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_IMAGE_TASK_NAME, type: HockeyKitImageTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_CLEAN_TASK_NAME, type: HockeyKitCleanTask, group: HOCKEYKIT_GROUP_NAME) + + DefaultTask hockeykitTask = project.task(HOCKEYKIT_TASK_NAME, type: DefaultTask, description: "Creates a build that can be deployed on a hockeykit Server", group: HOCKEYKIT_GROUP_NAME); + hockeykitTask.dependsOn(HOCKEYKIT_ARCHIVE_TASK_NAME, HOCKEYKIT_MANIFEST_TASK_NAME, HOCKEYKIT_IMAGE_TASK_NAME, HOCKEYKIT_NOTES_TASK_NAME) + } + + private void configureKeychain(Project project) { + project.task(KEYCHAIN_CREATE_TASK_NAME, type: KeychainCreateTask, group: XCODE_GROUP_NAME) + project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) + project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) + } - private void configureHockeyKit(Project project) { - project.task(HOCKEYKIT_MANIFEST_TASK_NAME, type: HockeyKitManifestTask, group: HOCKEYKIT_GROUP_NAME) - HockeyKitArchiveTask hockeyKitArchiveTask = project.task(HOCKEYKIT_ARCHIVE_TASK_NAME, type: HockeyKitArchiveTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_NOTES_TASK_NAME, type: HockeyKitReleaseNotesTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_IMAGE_TASK_NAME, type: HockeyKitImageTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_CLEAN_TASK_NAME, type: HockeyKitCleanTask, group: HOCKEYKIT_GROUP_NAME) + private void configureTest(Project project) { + project.task(XCODE_TEST_TASK_NAME, type: XcodeTestTask, group: XCODE_GROUP_NAME) + project.task(XCODE_BUILD_FOR_TEST_TASK_NAME, type: XcodeBuildForTestTask, group: XCODE_GROUP_NAME) + project.task(XCODE_TEST_RUN_TASK_NAME, type: XcodeTestRunTask, group: XCODE_GROUP_NAME) + + } + + private configureInfoPlist(Project project) { + project.task(INFOPLIST_MODIFY_TASK_NAME, type: InfoPlistModifyTask, group: XCODE_GROUP_NAME) + } + + private configureProvisioning(Project project) { + project.task(PROVISIONING_INSTALL_TASK_NAME, type: ProvisioningInstallTask, group: XCODE_GROUP_NAME) + project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) + } - DefaultTask hockeykitTask = project.task(HOCKEYKIT_TASK_NAME, type: DefaultTask, description: "Creates a build that can be deployed on a hockeykit Server", group: HOCKEYKIT_GROUP_NAME); - hockeykitTask.dependsOn(HOCKEYKIT_ARCHIVE_TASK_NAME, HOCKEYKIT_MANIFEST_TASK_NAME, HOCKEYKIT_IMAGE_TASK_NAME, HOCKEYKIT_NOTES_TASK_NAME) - } - - private void configureKeychain(Project project) { - project.task(KEYCHAIN_CREATE_TASK_NAME, type: KeychainCreateTask, group: XCODE_GROUP_NAME) - project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) - project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) - } - - private void configureTest(Project project) { - project.task(XCODE_TEST_TASK_NAME, type: XcodeTestTask, group: XCODE_GROUP_NAME) - project.task(XCODE_BUILD_FOR_TEST_TASK_NAME, type: XcodeBuildForTestTask, group: XCODE_GROUP_NAME) - project.task(XCODE_TEST_RUN_TASK_NAME, type: XcodeTestRunTask, group: XCODE_GROUP_NAME) - - } - - private configureInfoPlist(Project project) { - project.task(INFOPLIST_MODIFY_TASK_NAME, type: InfoPlistModifyTask, group: XCODE_GROUP_NAME) - } - - private configureProvisioning(Project project) { - project.task(PROVISIONING_INSTALL_TASK_NAME, type: ProvisioningInstallTask, group: XCODE_GROUP_NAME) - project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) - } - - private configurePackage(Project project) { - PackageTask packageTask = project.task(PACKAGE_TASK_NAME, type: PackageTask, group: XCODE_GROUP_NAME) - - - project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) - - //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) - - //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) + private configurePackage(Project project) { + PackageTask packageTask = project.task(PACKAGE_TASK_NAME, type: PackageTask, group: XCODE_GROUP_NAME) + + + project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) + + //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) + + //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) /* // disabled clean because of #115 packageTask.doLast { @@ -541,109 +547,109 @@ class XcodePlugin implements Plugin { keychainCleanupTask.clean() } */ - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) - packageTask.shouldRunAfter(xcodeBuildTask) - } + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) + packageTask.shouldRunAfter(xcodeBuildTask) + } - private configureAppstore(Project project) { - project.task(APPSTORE_UPLOAD_TASK_NAME, type: AppstoreUploadTask, group: APPSTORE_GROUP_NAME) - project.task(APPSTORE_VALIDATE_TASK_NAME, type: AppstoreValidateTask, group: APPSTORE_GROUP_NAME) - } + private configureAppstore(Project project) { + project.task(APPSTORE_UPLOAD_TASK_NAME, type: AppstoreUploadTask, group: APPSTORE_GROUP_NAME) + project.task(APPSTORE_VALIDATE_TASK_NAME, type: AppstoreValidateTask, group: APPSTORE_GROUP_NAME) + } - private void configureHockeyApp(Project project) { - project.task(HOCKEYAPP_CLEAN_TASK_NAME, type: HockeyAppCleanTask, group: HOCKEYAPP_GROUP_NAME) - project.task(HOCKEYAPP_TASK_NAME, type: HockeyAppUploadTask, group: HOCKEYAPP_GROUP_NAME) - } + private void configureHockeyApp(Project project) { + project.task(HOCKEYAPP_CLEAN_TASK_NAME, type: HockeyAppCleanTask, group: HOCKEYAPP_GROUP_NAME) + project.task(HOCKEYAPP_TASK_NAME, type: HockeyAppUploadTask, group: HOCKEYAPP_GROUP_NAME) + } - private void configureAppledoc(Project project) { - project.task(APPLEDOC_TASK_NAME, type: AppledocTask, group: APPLE_DOC_GROUP_NAME) - project.task(APPLEDOC_CLEAN_TASK_NAME, type: AppledocCleanTask, group: APPLE_DOC_GROUP_NAME) + private void configureAppledoc(Project project) { + project.task(APPLEDOC_TASK_NAME, type: AppledocTask, group: APPLE_DOC_GROUP_NAME) + project.task(APPLEDOC_CLEAN_TASK_NAME, type: AppledocCleanTask, group: APPLE_DOC_GROUP_NAME) - } + } - private void configureCoverage(Project project) { - project.task(COVERAGE_TASK_NAME, type: CoverageTask, group: COVERAGE_GROUP_NAME) - project.task(COVERAGE_CLEAN_TASK_NAME, type: CoverageCleanTask, group: COVERAGE_GROUP_NAME) + private void configureCoverage(Project project) { + project.task(COVERAGE_TASK_NAME, type: CoverageTask, group: COVERAGE_GROUP_NAME) + project.task(COVERAGE_CLEAN_TASK_NAME, type: CoverageCleanTask, group: COVERAGE_GROUP_NAME) - } + } - private void configureCpd(Project project) { - project.task(CPD_TASK_NAME, type: CpdTask, group: ANALYTICS_GROUP_NAME) - } + private void configureCpd(Project project) { + project.task(CPD_TASK_NAME, type: CpdTask, group: ANALYTICS_GROUP_NAME) + } - private void configureDeployGate(Project project) { - project.task(DEPLOYGATE_CLEAN_TASK_NAME, type: DeployGateCleanTask, group: DEPLOYGATE_GROUP_NAME) - project.task(DEPLOYGATE_TASK_NAME, type: DeployGateUploadTask, group: DEPLOYGATE_GROUP_NAME) - } + private void configureDeployGate(Project project) { + project.task(DEPLOYGATE_CLEAN_TASK_NAME, type: DeployGateCleanTask, group: DEPLOYGATE_GROUP_NAME) + project.task(DEPLOYGATE_TASK_NAME, type: DeployGateUploadTask, group: DEPLOYGATE_GROUP_NAME) + } - private void configureCrashlytics(Project project) { - project.task(CRASHLYTICS_TASK_NAME, type: CrashlyticsUploadTask, group: CRASHLYTICS_GROUP_NAME) - } + private void configureCrashlytics(Project project) { + project.task(CRASHLYTICS_TASK_NAME, type: CrashlyticsUploadTask, group: CRASHLYTICS_GROUP_NAME) + } - private void configureCocoapods(Project project) { - project.task(COCOAPODS_INSTALL_TASK_NAME, type: CocoapodsInstallTask, group: COCOAPODS_GROUP_NAME) - project.task(COCOAPODS_BOOTSTRAP_TASK_NAME, type: CocoapodsBootstrapTask, group: COCOAPODS_GROUP_NAME) - project.task(COCOAPODS_UPDATE_TASK_NAME, type: CocoapodsUpdateTask, group: COCOAPODS_GROUP_NAME) - } + private void configureCocoapods(Project project) { + project.task(COCOAPODS_INSTALL_TASK_NAME, type: CocoapodsInstallTask, group: COCOAPODS_GROUP_NAME) + project.task(COCOAPODS_BOOTSTRAP_TASK_NAME, type: CocoapodsBootstrapTask, group: COCOAPODS_GROUP_NAME) + project.task(COCOAPODS_UPDATE_TASK_NAME, type: CocoapodsUpdateTask, group: COCOAPODS_GROUP_NAME) + } - private configureCocoapodsDependencies(Project project) { - CocoapodsInstallTask cocoapodsInstallTask = project.getTasks().getByName(XcodePlugin.COCOAPODS_INSTALL_TASK_NAME) - if (cocoapodsInstallTask.hasPodfile()) { - addDependencyToBuild(project, cocoapodsInstallTask) - } - } + private configureCocoapodsDependencies(Project project) { + CocoapodsInstallTask cocoapodsInstallTask = project.getTasks().getByName(XcodePlugin.COCOAPODS_INSTALL_TASK_NAME) + if (cocoapodsInstallTask.hasPodfile()) { + addDependencyToBuild(project, cocoapodsInstallTask) + } + } - private void configureCarthage(Project project) { - project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) - project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) - } + private void configureCarthage(Project project) { + project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) + project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) + } - private configureCarthageDependencies(Project project) { - CarthageUpdateTask carthageUpdateTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME) - CarthageCleanTask carthageCleanTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_CLEAN_TASK_NAME) + private configureCarthageDependencies(Project project) { + CarthageUpdateTask carthageUpdateTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME) + CarthageCleanTask carthageCleanTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_CLEAN_TASK_NAME) - if (carthageUpdateTask.hasCartFile()) { - addDependencyToBuild(project, carthageUpdateTask) - project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(carthageCleanTask); - } - } + if (carthageUpdateTask.hasCartFile()) { + addDependencyToBuild(project, carthageUpdateTask) + project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(carthageCleanTask); + } + } - private void configureOCLint(Project project) { - OCLintTask reportTask = project.task(OCLINT_REPORT_TASK_NAME, type: OCLintTask, group: ANALYTICS_GROUP_NAME) + private void configureOCLint(Project project) { + OCLintTask reportTask = project.task(OCLINT_REPORT_TASK_NAME, type: OCLintTask, group: ANALYTICS_GROUP_NAME) - Task ocLintTask = project.getTasks().create(OCLINT_TASK_NAME); - ocLintTask.group = ANALYTICS_GROUP_NAME - ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME - ocLintTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)) + Task ocLintTask = project.getTasks().create(OCLINT_TASK_NAME); + ocLintTask.group = ANALYTICS_GROUP_NAME + ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME + ocLintTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)) - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XcodePlugin.XCODE_BUILD_TASK_NAME) - reportTask.mustRunAfter(xcodeBuildTask) + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XcodePlugin.XCODE_BUILD_TASK_NAME) + reportTask.mustRunAfter(xcodeBuildTask) - ocLintTask.dependsOn(xcodeBuildTask) - ocLintTask.dependsOn(reportTask) + ocLintTask.dependsOn(xcodeBuildTask) + ocLintTask.dependsOn(reportTask) - } + } - private void addDependencyToBuild(Project project, Task task) { - logger.info("add task dependency for {}", task) + private void addDependencyToBuild(Project project, Task task) { + logger.info("add task dependency for {}", task) - for (Task buildTask : project.getTasks().withType(XcodeBuildTask.class)) { - buildTask.dependsOn(task) - } + for (Task buildTask : project.getTasks().withType(XcodeBuildTask.class)) { + buildTask.dependsOn(task) + } - for (Task testTask : project.getTasks().withType(XcodeTestTask.class)) { - testTask.dependsOn(task) - } + for (Task testTask : project.getTasks().withType(XcodeTestTask.class)) { + testTask.dependsOn(task) + } - for (Task buildForTestTask : project.getTasks().withType(XcodeBuildForTestTask.class)) { - logger.info("add task depencency for {}", buildForTestTask) - buildForTestTask.dependsOn(task) - } + for (Task buildForTestTask : project.getTasks().withType(XcodeBuildForTestTask.class)) { + logger.info("add task depencency for {}", buildForTestTask) + buildForTestTask.dependsOn(task) + } - } + } } From 7e2415674fa3d226e7644bb8fa7e47360bd69e35 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 25 Apr 2018 09:57:33 +0100 Subject: [PATCH 041/121] Work in progress --- .../codesign/ProvisioningProfileReader.groovy | 8 + .../org/openbakery/util/PathHelper.groovy | 7 + .../openbakery/AbstractXcodeBuildTask.groovy | 9 +- .../org/openbakery/InfoPlistExtension.groovy | 26 +- .../org/openbakery/InfoPlistModifyTask.groovy | 8 +- .../PrepareXcodeArchivingTask.groovy | 84 ++ .../openbakery/XcodeBuildArchiveTask.groovy | 1001 ++++++++--------- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 43 +- .../groovy/org/openbakery/XcodePlugin.groovy | 10 +- 9 files changed, 638 insertions(+), 558 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy index ead64e05..2ab62d04 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy @@ -159,6 +159,14 @@ class ProvisioningProfileReader { return config.getString("TeamIdentifier") } + String getTeamName() { + return config.getString("TeamName") + } + + String getName() { + return config.getString("Name") + } + File getPlistFromProvisioningProfile() { if (provisioningPlist == null) { // unpack provisioning profile to plain plist diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index 53d5f3e9..5485f1fb 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -1,6 +1,7 @@ package org.openbakery.util import groovy.transform.CompileStatic +import org.gradle.api.Project import org.openbakery.xcode.Type @CompileStatic @@ -10,6 +11,8 @@ class PathHelper { public static final String IPHONE_SIMULATOR = "iphonesimulator" public static final String IPHONE_OS = "iphoneos" + private static final String FOLDER_ARCHIVE = "archive" + static File resolvePath(Type type, boolean simulator, File symRoot, @@ -64,6 +67,10 @@ class PathHelper { configuration) } + static File resolveArchiveFolder(Project project) { + return new File(project.getBuildDir(), FOLDER_ARCHIVE) + } + private static File resolveSymRoot(File symRoot, String configuration, String destination) { diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index edb69c97..f4426f1c 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -6,13 +6,11 @@ import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.internal.logging.text.StyledTextOutput import org.gradle.internal.logging.text.StyledTextOutputFactory import org.gradle.util.ConfigureUtil -import org.openbakery.codesign.Security import org.openbakery.output.XcodeBuildOutputAppender import org.openbakery.xcode.Destination import org.openbakery.xcode.Devices import org.openbakery.xcode.Type import org.openbakery.xcode.XcodebuildParameters - /** * User: rene * Date: 15.07.13 @@ -96,4 +94,11 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { return new XcodeBuildOutputAppender(progressLogger, output) } + XcodeBuildPluginExtension getXcodeExtension() { + return project.getExtensions().getByType(XcodeBuildPluginExtension.class) + } + + InfoPlistExtension getInfoPlistExtension() { + return project.getExtensions().getByType(InfoPlistExtension.class) + } } diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy index 069ac692..2f23eb47 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy @@ -16,18 +16,18 @@ package org.openbakery class InfoPlistExtension { - def String bundleIdentifier = null - def String bundleIdentifierSuffix = null - def String bundleName = null - def String bundleDisplayName = null - def String bundleDisplayNameSuffix = null - def String version = null - def String versionSuffix = null - def String versionPrefix = null - def String shortVersionString = null - def String shortVersionStringSuffix = null - def String shortVersionStringPrefix = null - def List commands = null + String bundleIdentifier = null + String bundleIdentifierSuffix = null + String bundleName = null + String bundleDisplayName = null + String bundleDisplayNameSuffix = null + String version = null + String versionSuffix = null + String versionPrefix = null + String shortVersionString = null + String shortVersionStringSuffix = null + String shortVersionStringPrefix = null + List commands = null @@ -54,4 +54,4 @@ class InfoPlistExtension { shortVersionStringPrefix != null || commands != null; } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 97116028..22aab15c 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -27,9 +27,6 @@ class InfoPlistModifyTask extends AbstractDistributeTask { dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) } - - - @TaskAction def prepare() { @@ -56,6 +53,7 @@ class InfoPlistModifyTask extends AbstractDistributeTask { if (project.infoplist.bundleIdentifierSuffix != null) { def bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") setValueForPlist("CFBundleIdentifier", bundleIdentifier + project.infoplist.bundleIdentifierSuffix) + println "// add suffix to bundleIdentifier : " + bundleIdentifier + " //// " + project.infoplist.bundleIdentifierSuffix } // Modify bundle bundleName @@ -151,14 +149,12 @@ class InfoPlistModifyTask extends AbstractDistributeTask { modfied = true logger.lifecycle("Set {} to {}", key, value) plistHelper.setValueForPlist(infoPlist, key, value) - } - void setValueForPlist(String command) { modfied = true logger.lifecycle("Set {}", command) plistHelper.commandForPlist(infoPlist, command) } -} \ 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 new file mode 100644 index 00000000..96db142f --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -0,0 +1,84 @@ +package org.openbakery + +import groovy.transform.CompileStatic +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.PathHelper + +@CompileStatic +class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { + + private ProvisioningProfileReader reader + + public static final String NAME = "prepareArchiving" + + private static final String FILE_NAME = "archive.xcconfig" + private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" + private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" + private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" + private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" + private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" + + PrepareXcodeArchivingTask() { + super() + dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) + dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) + + this.description = "Prepare the archive configuration file" + } + + @Input + List getProvisioningUriList() { + return getXcodeExtension().signing.mobileProvisionURI + } + + @Input + String getBundleIdentifier() { + File plistFile = new File(project.projectDir, getXcodeExtension().getInfoPlist()) + return plistHelper.getValueFromPlist(plistFile, "CFBundleIdentifier") + } + + Optional getProvisioningFile() { + List provisioningList = getProvisioningUriList() + .collect { it -> new File(new URI(it)) } + + return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, + provisioningList, + commandRunner, + plistHelper)) + } + + @OutputFile + File getXcConfigFile() { + return new File(PathHelper.resolveArchiveFolder(project), FILE_NAME) + } + + @TaskAction + void generate() { + getXcConfigFile().text = "//:configuration = GradleXcode" + computeProvisioningFile(getProvisioningFile() + .orElseThrow { new IllegalArgumentException() }) + } + + private void computeProvisioningFile(File file) { + reader = new ProvisioningProfileReader(file, commandRunner) + append(KEY_CODE_SIGN_IDENTITY, getCodeSignIdentity()) + append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) + append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) + append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) + append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) + } + + private String getCodeSignIdentity() { + return "iPhone Distribution: " + + reader.getTeamName() + + " (" + reader.getTeamIdentifierPrefix() + ")" + } + + private void append(String key, String value) { + getXcConfigFile() + .append(System.getProperty("line.separator") + key + " = " + value) + } +} diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index cef408a0..cc48cdaf 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -17,520 +17,513 @@ package org.openbakery import groovy.io.FileType import org.apache.commons.io.FileUtils -import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.xcode.Extension import org.openbakery.xcode.Type +import org.openbakery.xcode.Extension import org.openbakery.xcode.Xcodebuild -import java.util.regex.Pattern - import static groovy.io.FileType.FILES class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { - public static final String ARCHIVE_FOLDER = "archive" - - private static final Pattern ICON_FILE_MATCHER = ~/Icon(-\d+)??\.png/ - - XcodeBuildArchiveTask() { - super() - - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) - // when creating an xcarchive for iOS then the provisioning profile is need for the team id so that the entitlements is setup properly - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - this.description = "Prepare the app bundle that it can be archive" - } - - @OutputDirectory - File getOutputDirectory() { - def archiveDirectory = new File(project.getBuildDir(), ARCHIVE_FOLDER) - archiveDirectory.mkdirs() - return archiveDirectory - } - - @TaskAction - def archive() { -// if (project.xcodebuild.useXcodebuildArchive) { -// - File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - commandRunner.setOutputFile(outputFile) - - commandRunner.run("xcodebuild", - "archive", - "-scheme", - project.xcodebuild.scheme, - "-archivePath", - new File(project.buildDir, "archive/" + project.xcodebuild.scheme + ".xcarchive").absolutePath, - "-xcconfig", "test.xcconfig") - -// xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), -// project.xcodebuild.environment, -// getArchiveDirectory().absolutePath) - -// return -//// } - -// parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) -//// if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { -//// logger.debug("Create zip archive") -//// -//// // create zip archive -//// String zipFileName = parameters.bundleName -//// if (project.xcodebuild.bundleNameSuffix != null) { -//// zipFileName += project.xcodebuild.bundleNameSuffix -//// } -//// zipFileName += ".zip" -//// -//// def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) -//// def baseDirectory = parameters.applicationBundle.parentFile -//// -//// createZip(zipFile, baseDirectory, parameters.applicationBundle) -//// return -//// } -// -// logger.debug("Create xcarchive") -// Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) -// -//// if (project.xcodebuild.useXcodebuildArchive) { -// -// File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") -// commandRunner.setOutputFile(outputFile) -// -// xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) -// -// return -//// } -// -// // create xcarchive -// // copy application bundle -// copy(parameters.applicationBundle, getApplicationsDirectory()) -// -// File onDemandResources = new File(parameters.outputPath, "OnDemandResources") -// if (onDemandResources.exists()) { -// copy(onDemandResources, getProductsDirectory()) -// } -// -// // copy onDemandResources -// -// def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") -// dSymDirectory.mkdirs() -// copyDsyms(parameters.outputPath, dSymDirectory) -// -// List appBundles = getAppBundles(parameters.outputPath) -// for (File bundle : appBundles) { -// createEntitlements(bundle) -// createExtensionSupportDirectory(bundle, xcodebuild) -// } -// -// File applicationsDirectory = getApplicationsDirectory() -// -// File archiveDirectory = getArchiveDirectory() -// createInfoPlist(archiveDirectory) -// createFrameworks(archiveDirectory, xcodebuild) -// deleteEmptyFrameworks(archiveDirectory) -// deleteXCTestIfExists(applicationsDirectory) -// deleteFrameworksInExtension(applicationsDirectory) -// copyBCSymbolMaps(archiveDirectory) -// -// if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { -// File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) -// convertInfoPlistToBinary(applicationFolder) -// -// removeUnneededDylibsFromBundle(applicationFolder) -// } -// -// logger.debug("create archive done") - } - - - ArrayList getiOSIcons() { - return parameters.applicationBundle - .list() - .findAll { it.matches(ICON_FILE_MATCHER) } - .collect { "Applications/" + parameters.applicationBundleName + "/" + it } - } - - ArrayList getMacOSXIcons() { - File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") - return Optional.ofNullable(plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile")) - .filter { it -> return !it.empty } - .map { it -> ["Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + it + ".icns"] } - .orElse([]) - } - - def getValueFromBundleInfoPlist(File bundle, String key) { - File appInfoPlist - if (parameters.type == Type.macOS) { - appInfoPlist = new File(bundle, "Contents/Info.plist") - } else { - appInfoPlist = new File(bundle, "Info.plist") - } - return plistHelper.getValueFromPlist(appInfoPlist, key) - } - - - def createInfoPlist(def applicationsDirectory) { - - StringBuilder content = new StringBuilder(); - - - def name = parameters.bundleName - def schemeName = name - def applicationPath = "Applications/" + parameters.applicationBundleName - def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") - int time = System.currentTimeMillis() / 1000; - - def creationDate = formatDate(new Date()); - - def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") - def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") - - List icons - if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { - icons = getiOSIcons() - } else { - icons = getMacOSXIcons() - } - - content.append("\n") - content.append("\n") - content.append("\n") - content.append("\n") - content.append(" ApplicationProperties\n") - content.append(" \n") - content.append(" ApplicationPath\n") - content.append(" " + applicationPath + "\n") - content.append(" CFBundleIdentifier\n") - content.append(" " + bundleIdentifier + "\n") - - if (shortBundleVersion != null) { - content.append(" CFBundleShortVersionString\n") - content.append(" " + shortBundleVersion + "\n") - } - - if (bundleVersion != null) { - content.append(" CFBundleVersion\n") - content.append(" " + bundleVersion + "\n") - } - - if (getSigningIdentity()) { - content.append(" SigningIdentity\n") - content.append(" " + getSigningIdentity() + "\n") - - } - - if (icons.size() > 0) { - content.append(" IconPaths\n") - content.append(" \n") - for (String icon : icons) { - content.append(" " + icon + "\n") - } - content.append(" \n") - } - - content.append(" \n") - content.append(" ArchiveVersion\n") - content.append(" 2\n") - content.append(" CreationDate\n") - content.append(" " + creationDate + "\n") - content.append(" Name\n") - content.append(" " + name + "\n") - content.append(" SchemeName\n") - content.append(" " + schemeName + "\n") - content.append("\n") - content.append("") - - File infoPlist = new File(applicationsDirectory, "Info.plist") - FileUtils.writeStringToFile(infoPlist, content.toString()) - } - - - def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { - - File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") - if (frameworksPath.exists()) { - - - def libNames = [] - frameworksPath.eachFile() { - libNames.add(it.getName()) - } - - logger.debug("swiftlibs to add: {}", libNames); + public static final String ARCHIVE_FOLDER = "archive" + + XcodeBuildArchiveTask() { + super() + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) + // when creating an xcarchive for iOS then the provisioning profile is need for the team id so that the entitlements is setup properly + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + this.description = "Prepare the app bundle that it can be archive" + } + + + def getOutputDirectory() { + def archiveDirectory = new File(project.getBuildDir(), ARCHIVE_FOLDER) + archiveDirectory.mkdirs() + return archiveDirectory + } + + + def getiOSIcons() { + ArrayList icons = new ArrayList<>(); + + File applicationBundle = parameters.applicationBundle + def fileList = applicationBundle.list( + [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png + ).toList() + + def applicationPath = "Applications/" + parameters.applicationBundleName + + for (String item in fileList) { + icons.add(applicationPath + "/" + item) + } + + + return icons + } + + def getMacOSXIcons() { + File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") + ArrayList icons = new ArrayList<>(); + + def icnsFileName = plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile") + + if (icnsFileName == null || icnsFileName == "") { + return icons + } + + def iconPath = "Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + icnsFileName + ".icns" + icons.add(iconPath) + + return icons + } + + + def getValueFromBundleInfoPlist(File bundle, String key) { + File appInfoPlist + if (parameters.type == Type.macOS) { + appInfoPlist = new File(bundle, "Contents/Info.plist") + } else { + appInfoPlist = new File(bundle, "Info.plist") + } + return plistHelper.getValueFromPlist(appInfoPlist, key) + } + + + def createInfoPlist(def applicationsDirectory) { + + StringBuilder content = new StringBuilder(); + + + def name = parameters.bundleName + def schemeName = name + def applicationPath = "Applications/" + parameters.applicationBundleName + def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") + int time = System.currentTimeMillis() / 1000; + + def creationDate = formatDate(new Date()); + + def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") + def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") + + List icons + if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { + icons = getiOSIcons() + } else { + icons = getMacOSXIcons() + } + + content.append("\n") + content.append("\n") + content.append("\n") + content.append("\n") + content.append(" ApplicationProperties\n") + content.append(" \n") + content.append(" ApplicationPath\n") + content.append(" " + applicationPath + "\n") + content.append(" CFBundleIdentifier\n") + content.append(" " + bundleIdentifier + "\n") + + if (shortBundleVersion != null) { + content.append(" CFBundleShortVersionString\n") + content.append(" " + shortBundleVersion + "\n") + } + + if (bundleVersion != null) { + content.append(" CFBundleVersion\n") + content.append(" " + bundleVersion + "\n") + } + + if (getSigningIdentity()) { + content.append(" SigningIdentity\n") + content.append(" " + getSigningIdentity() + "\n") + + } + + if (icons.size() > 0) { + content.append(" IconPaths\n") + content.append(" \n") + for (String icon : icons) { + content.append(" " + icon + "\n") + } + content.append(" \n") + } + + content.append(" \n") + content.append(" ArchiveVersion\n") + content.append(" 2\n") + content.append(" CreationDate\n") + content.append(" " + creationDate + "\n") + content.append(" Name\n") + content.append(" " + name + "\n") + content.append(" SchemeName\n") + content.append(" " + schemeName + "\n") + content.append("\n") + content.append("") + + File infoPlist = new File(applicationsDirectory, "Info.plist") + FileUtils.writeStringToFile(infoPlist, content.toString()) + } + + + def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { + + File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") + if (frameworksPath.exists()) { + + + def libNames = [] + frameworksPath.eachFile() { + libNames.add(it.getName()) + } + + logger.debug("swiftlibs to add: {}", libNames); - File swiftLibs = new File(xcodebuild.getToolchainDirectory(), - "usr/lib/swift/" + getSwiftLibFolderName()) - - logger.debug("swiftlibs to add: {}", swiftLibs); - - swiftLibs.eachFile() { - logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) - if (libNames.contains(it.name)) { - copy(it, getSwiftSupportDirectory()) - } - } - } - - } - - public String getSwiftLibFolderName() { - String result - switch (parameters.type) { - case Type.tvOS: - result = "appletvos" - break - - case Type.iOS: - result = "iphoneos" - break - - default: - break - } - - return result - } - - def getSwiftSupportDirectory() { - def swiftSupportPath = "SwiftSupport" - - if (xcode.version.major > 6) { - swiftSupportPath += "/" + getSwiftLibFolderName() - } - - File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) - if (!swiftSupportDirectory.exists()) { - swiftSupportDirectory.mkdirs() - } - return swiftSupportDirectory - } - - def deleteDirectoryIfEmpty(File base, String child) { - File directory = new File(base, child) - if (directory.exists() && directory.list().length == 0) { - directory.deleteDir(); - } - } - - def deleteEmptyFrameworks(File applicationsDirectory) { - // if frameworks directory is emtpy - File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) - deleteDirectoryIfEmpty(appPath, "Frameworks") - - - } - - def deleteFrameworksInExtension(File applicationsDirectory) { - - - File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") - if (!plugins.exists()) { - return - } - - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith(".appex")) { - File frameworkDirectory = new File(file, "Frameworks"); - if (frameworkDirectory.exists()) { - FileUtils.deleteDirectory(frameworkDirectory) - } - } - } - - } - - - def copyDsyms(File archiveDirectory, File dSymDirectory) { - - archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> - if (directory.toString().toLowerCase().endsWith(".dsym")) { - copy(directory, dSymDirectory) - } - } - - } - - def createEntitlements(File bundle) { - - if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { - logger.warn("Entitlements handling is only implemented for iOS and tvOS!") - return - } - - String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") - if (bundleIdentifier == null) { - logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) - return - } - BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) - if (buildConfiguration == null) { - logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) - return - } - - File destinationDirectory = getDestinationDirectoryForBundle(bundle) - if (buildConfiguration.entitlements) { - File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") - FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) - modifyEntitlementsFile(entitlementFile, bundleIdentifier) - } - } - - def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { - if (!entitlementFile.exists()) { - logger.warn("Entitlements File does not exist {}", entitlementFile) - return - } - - String applicationIdentifier = "UNKNOWN00ID"; - // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback - File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) - if (provisioningProfile != null && provisioningProfile.exists()) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) - applicationIdentifier = reader.getApplicationIdentifierPrefix() - } - - plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) - - List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") - - if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { - def modifiedKeychainAccessGroups = [] - keychainAccessGroups.each() { group -> - modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") - } - plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) - } - } - - def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { - String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") - if (extensionIdentifier == null) { - logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) - return - } - - Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) - if (extension == null) { - logger.warn("Extension type not supported", extensionIdentifier) - return - } - - switch (extension) { - case Extension.sticker: - File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") - if (supportDirectory.mkdirs()) { - File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") - copy(stub, supportDirectory) - } - break - default: - break - } - } - - - def copyBCSymbolMaps(File archiveDirectory) { - if (!parameters.bitcode) { - logger.debug("bitcode is not activated, so to not create BCSymbolMaps") - return - } - File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") - bcSymbolMapsDirectory.mkdirs() - - parameters.outputPath.eachFileRecurse { file -> - if (file.toString().endsWith(".bcsymbolmap")) { - FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) - } - } - - } - - // TODO: Define a `exportOptionsPlist` to avoid that kind of issue - def removeUnneededDylibsFromBundle(File bundle) { - File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") - if (libswiftRemoteMirror.exists()) { - libswiftRemoteMirror.delete() - } - } - - def deleteXCTestIfExists(File applicationsDirectory) { - File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") - if (!plugins.exists()) { - return - } - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith("xctest")) { - FileUtils.deleteDirectory(file) - return true - } - } - } - - File getProductsDirectory() { - File productsDirectory = new File(getArchiveDirectory(), "Products") - productsDirectory.mkdirs() - return productsDirectory - } - - File getApplicationsDirectory() { - File applicationsDirectory = new File(getProductsDirectory(), "Applications") - applicationsDirectory.mkdirs() - return applicationsDirectory - } - - File getDestinationDirectoryForBundle(File bundle) { - String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); - return new File(getApplicationsDirectory(), relative) - } - - def convertInfoPlistToBinary(File archiveDirectory) { - - archiveDirectory.eachFileRecurse(FILES) { - if (it.name.endsWith('.plist')) { - logger.debug("convert plist to binary {}", it) - def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] - try { - commandRunner.run(commandList) - } catch (CommandRunnerException ex) { - logger.lifecycle("Unable to convert!") - } - } - } - - } - - - def removeResourceRules(File appDirectory) { - - File resourceRules = new File(appDirectory, "ResourceRules.plist") - logger.lifecycle("delete {}", resourceRules) - if (resourceRules.exists()) { - resourceRules.delete() - } - - logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) - - setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") - - } - - - File getArchiveDirectory() { - - def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName - - if (project.xcodebuild.bundleNameSuffix != null) { - archiveDirectoryName += project.xcodebuild.bundleNameSuffix - } - archiveDirectoryName += ".xcarchive" - - def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) - archiveDirectory.mkdirs() - return archiveDirectory - } + File swiftLibs = new File(xcodebuild.getToolchainDirectory(), + "usr/lib/swift/" + getSwiftLibFolderName()) + + logger.debug("swiftlibs to add: {}", swiftLibs); + + swiftLibs.eachFile() { + logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) + if (libNames.contains(it.name)) { + copy(it, getSwiftSupportDirectory()) + } + } + } + + } + + public String getSwiftLibFolderName() { + String result + switch (parameters.type) { + case Type.tvOS: + result = "appletvos" + break + + case Type.iOS: + result = "iphoneos" + break + + default: + break + } + + return result + } + + def getSwiftSupportDirectory() { + def swiftSupportPath = "SwiftSupport" + + if (xcode.version.major > 6) { + swiftSupportPath += "/" + getSwiftLibFolderName() + } + + File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) + if (!swiftSupportDirectory.exists()) { + swiftSupportDirectory.mkdirs() + } + return swiftSupportDirectory + } + + def deleteDirectoryIfEmpty(File base, String child) { + File directory = new File(base, child) + if (directory.exists() && directory.list().length == 0) { + directory.deleteDir(); + } + } + + def deleteEmptyFrameworks(File applicationsDirectory) { + // if frameworks directory is emtpy + File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) + deleteDirectoryIfEmpty(appPath, "Frameworks") + + + } + + def deleteFrameworksInExtension(File applicationsDirectory) { + + + File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") + if (!plugins.exists()) { + return + } + + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith(".appex")) { + File frameworkDirectory = new File(file, "Frameworks"); + if (frameworkDirectory.exists()) { + FileUtils.deleteDirectory(frameworkDirectory) + } + } + } + + } + + + def copyDsyms(File archiveDirectory, File dSymDirectory) { + + archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> + if (directory.toString().toLowerCase().endsWith(".dsym")) { + copy(directory, dSymDirectory) + } + } + + } + + def createEntitlements(File bundle) { + + if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { + logger.warn("Entitlements handling is only implemented for iOS and tvOS!") + return + } + + String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") + if (bundleIdentifier == null) { + logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) + return + } + BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) + if (buildConfiguration == null) { + logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) + return + } + + File destinationDirectory = getDestinationDirectoryForBundle(bundle) + if (buildConfiguration.entitlements) { + File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") + FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) + modifyEntitlementsFile(entitlementFile, bundleIdentifier) + } + } + + def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { + if (!entitlementFile.exists()) { + logger.warn("Entitlements File does not exist {}", entitlementFile) + return + } + + String applicationIdentifier = "UNKNOWN00ID"; // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback + File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) + if (provisioningProfile != null && provisioningProfile.exists()) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) + applicationIdentifier = reader.getApplicationIdentifierPrefix() + } + + plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) + + List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") + + if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { + def modifiedKeychainAccessGroups = [] + keychainAccessGroups.each() { group -> + modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") + } + plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) + } + } + + def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { + String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") + if (extensionIdentifier == null) { + logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) + return + } + + Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) + if (extension == null) { + logger.warn("Extension type not supported", extensionIdentifier) + return + } + + switch (extension) { + case Extension.sticker: + File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") + if (supportDirectory.mkdirs()) { + File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") + copy(stub, supportDirectory) + } + break + default: + break + } + } + + @TaskAction + def archive() { + parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) + if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { + logger.debug("Create zip archive") + + // create zip archive + String zipFileName = parameters.bundleName + if (project.xcodebuild.bundleNameSuffix != null) { + zipFileName += project.xcodebuild.bundleNameSuffix + } + zipFileName += ".zip" + + def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) + def baseDirectory = parameters.applicationBundle.parentFile + + createZip(zipFile, baseDirectory, parameters.applicationBundle) + return + } + + logger.debug("Create xcarchive") + Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) + + if (project.xcodebuild.useXcodebuildArchive) { + + File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + commandRunner.setOutputFile(outputFile) + + xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) + + return + } + + // create xcarchive + // copy application bundle + copy(parameters.applicationBundle, getApplicationsDirectory()) + + File onDemandResources = new File(parameters.outputPath, "OnDemandResources") + if (onDemandResources.exists()) { + copy(onDemandResources, getProductsDirectory()) + } + + // copy onDemandResources + + def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") + dSymDirectory.mkdirs() + copyDsyms(parameters.outputPath, dSymDirectory) + + List appBundles = getAppBundles(parameters.outputPath) + for (File bundle : appBundles) { + createEntitlements(bundle) + createExtensionSupportDirectory(bundle, xcodebuild) + } + + File applicationsDirectory = getApplicationsDirectory() + + File archiveDirectory = getArchiveDirectory() + createInfoPlist(archiveDirectory) + createFrameworks(archiveDirectory, xcodebuild) + deleteEmptyFrameworks(archiveDirectory) + deleteXCTestIfExists(applicationsDirectory) + deleteFrameworksInExtension(applicationsDirectory) + copyBCSymbolMaps(archiveDirectory) + + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { + File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) + convertInfoPlistToBinary(applicationFolder) + + removeUnneededDylibsFromBundle(applicationFolder) + } + + logger.debug("create archive done") + } + + def copyBCSymbolMaps(File archiveDirectory) { + if (!parameters.bitcode) { + logger.debug("bitcode is not activated, so to not create BCSymbolMaps") + return + } + File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") + bcSymbolMapsDirectory.mkdirs() + + parameters.outputPath.eachFileRecurse { file -> + if (file.toString().endsWith(".bcsymbolmap")) { + FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) + } + } + + } + + // TODO: Define a `exportOptionsPlist` to avoid that kind of issue + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } + + def deleteXCTestIfExists(File applicationsDirectory) { + File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") + if (!plugins.exists()) { + return + } + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith("xctest")) { + FileUtils.deleteDirectory(file) + return true + } + } + } + + File getProductsDirectory() { + File productsDirectory = new File(getArchiveDirectory(), "Products") + productsDirectory.mkdirs() + return productsDirectory + } + + File getApplicationsDirectory() { + File applicationsDirectory = new File(getProductsDirectory(), "Applications") + applicationsDirectory.mkdirs() + return applicationsDirectory + } + + File getDestinationDirectoryForBundle(File bundle) { + String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); + return new File(getApplicationsDirectory(), relative) + } + + def convertInfoPlistToBinary(File archiveDirectory) { + + archiveDirectory.eachFileRecurse(FILES) { + if (it.name.endsWith('.plist')) { + logger.debug("convert plist to binary {}", it) + def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] + try { + commandRunner.run(commandList) + } catch (CommandRunnerException ex) { + logger.lifecycle("Unable to convert!") + } + } + } + + } + + + def removeResourceRules(File appDirectory) { + + File resourceRules = new File(appDirectory, "ResourceRules.plist") + logger.lifecycle("delete {}", resourceRules) + if (resourceRules.exists()) { + resourceRules.delete() + } + + logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) + + setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") + + } + + + File getArchiveDirectory() { + + def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName + + if (project.xcodebuild.bundleNameSuffix != null) { + archiveDirectoryName += project.xcodebuild.bundleNameSuffix + } + archiveDirectoryName += ".xcarchive" + + def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) + archiveDirectory.mkdirs() + return archiveDirectory + } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index fd545346..b9c24d4a 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -16,35 +16,35 @@ package org.openbakery import org.gradle.api.tasks.* -import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.PathHelper import org.openbakery.xcode.Xcodebuild //@CompileStatic class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - public static final String FOLDER_ARCHIVE = "archive" - public static final String FOLDER_XCCONFIG = "xcconfig" + public static final String NAME = "archive" XcodeBuildArchiveTaskIosAndTvOS() { super() dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(PrepareXcodeArchivingTask.NAME) this.description = "Prepare the app bundle that it can be archive" } + @InputFile + File getXcConfigFile() { + return new File(PathHelper.resolveArchiveFolder(project), + PrepareXcodeArchivingTask.FILE_NAME) + } + @Input String getScheme() { return project.xcodebuild.scheme } - @InputFile - @Optional - File getProvisioningFile() { - return project.xcodebuild.signing.mobileProvisionFile.first() - } - @OutputFile File getOutputTextFile() { File file = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") @@ -53,33 +53,14 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @OutputDirectory File getOutputDirectory() { - def archiveDirectory = new File(project.getBuildDir(), FOLDER_ARCHIVE - + "/" + project.xcodebuild.scheme + ".xcarchive") + File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), + getScheme() + ".xcarchive") archiveDirectory.mkdirs() return archiveDirectory } - @OutputFile - File getXcconfigFile() { - return new File(getOutputDirectory(), "project.xcconfig") - } - @TaskAction private void archive() { - generateXConfigFile() - runArchiving() - } - - private void generateXConfigFile() { - File file = getProvisioningFile() - if (file.exists()) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(file, commandRunner) - println reader.getTeamIdentifierPrefix() - println reader.getUUID() - } - } - - private void runArchiving() { Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, @@ -90,6 +71,6 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { xcodebuild.archive(getScheme(), getOutputDirectory(), - project.file("test.xcconfig")) + getXcConfigFile()) } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 220af21e..66763e69 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -477,9 +477,15 @@ class XcodePlugin implements Plugin { private void configureArchive(Project project) { if (project.xcodebuild.type == Type.tvOS || project.xcodebuild.type == Type.iOS) { - XcodeBuildArchiveTaskIosAndTvOS task = project.tasks.create(ARCHIVE_TASK_NAME, + PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.tasks.create( + PrepareXcodeArchivingTask.NAME, + PrepareXcodeArchivingTask.class) + prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) + + XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.tasks.create( + XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) - task.setGroup(XCODE_GROUP_NAME) + archiveTask.setGroup(XCODE_GROUP_NAME) } else { XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); From 5bc4c0cbec4cc0fff5500d3fda8226c66ce393d2 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 25 Apr 2018 10:03:52 +0100 Subject: [PATCH 042/121] Revert indentation changes --- .../org/openbakery/InfoPlistModifyTask.groovy | 1 - .../groovy/org/openbakery/XcodePlugin.groovy | 1096 ++++++++--------- 2 files changed, 548 insertions(+), 549 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 22aab15c..417c45c9 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -53,7 +53,6 @@ class InfoPlistModifyTask extends AbstractDistributeTask { if (project.infoplist.bundleIdentifierSuffix != null) { def bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") setValueForPlist("CFBundleIdentifier", bundleIdentifier + project.infoplist.bundleIdentifierSuffix) - println "// add suffix to bundleIdentifier : " + bundleIdentifier + " //// " + project.infoplist.bundleIdentifierSuffix } // Modify bundle bundleName diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 66763e69..9442da30 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -73,479 +73,479 @@ import org.slf4j.LoggerFactory class XcodePlugin implements Plugin { - private static Logger logger = LoggerFactory.getLogger(XcodePlugin.class) - - public static final String XCODE_GROUP_NAME = "Xcode" - public static final String HOCKEYKIT_GROUP_NAME = "HockeyKit" - public static final String HOCKEYAPP_GROUP_NAME = "HockeyApp" - public static final String APPSTORE_GROUP_NAME = "AppStore" - public static final String DEPLOYGATE_GROUP_NAME = "DeployGate" - public static final String CRASHLYTICS_GROUP_NAME = "Crashlytics" - public static final String APPLE_DOC_GROUP_NAME = "Appledoc" - public static final String COVERAGE_GROUP_NAME = "Coverage" - public static final String COCOAPODS_GROUP_NAME = "Cocoapods" - public static final String CARTHAGE_GROUP_NAME = "Carthage" - public static final String SIMULATORS_GROUP_NAME = "Simulators" - public static final String ANALYTICS_GROUP_NAME = "Analytics" - - - public static final String XCODE_TEST_TASK_NAME = "xcodetest" - public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" - public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" - public static final String ARCHIVE_TASK_NAME = "archive" - public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" - public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" - public static final String SIMULATORS_CLEAN_TASK_NAME = "simulatorsClean" - public static final String SIMULATORS_START_TASK_NAME = "simulatorStart" - public static final String SIMULATORS_INSTALL_APP_TASK_NAME = "simulatorInstallApp" - public static final String SIMULATORS_RUN_APP_TASK_NAME = "simulatorRunApp" - public static final String SIMULATORS_KILL_TASK_NAME = "simulatorKill" - public static final String XCODE_BUILD_TASK_NAME = "xcodebuild" - public static final String XCODE_CLEAN_TASK_NAME = "xcodebuildClean" - public static final String XCODE_CONFIG_TASK_NAME = "xcodebuildConfig" - public static final String HOCKEYKIT_MANIFEST_TASK_NAME = "hockeykitManifest" - public static final String HOCKEYKIT_ARCHIVE_TASK_NAME = "hockeykitArchive" - public static final String HOCKEYKIT_NOTES_TASK_NAME = "hockeykitNotes" - public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" - public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" - public static final String HOCKEYKIT_TASK_NAME = "hockeykit" - public static final String KEYCHAIN_CREATE_TASK_NAME = "keychainCreate" - public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" - public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" - public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' - public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' - public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' - public static final String PACKAGE_TASK_NAME = 'package' - public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' - public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' - public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' - public static final String HOCKEYAPP_CLEAN_TASK_NAME = 'hockeyappClean' - public static final String HOCKEYAPP_TASK_NAME = 'hockeyapp' - public static final String DEPLOYGATE_TASK_NAME = 'deploygate' - public static final String DEPLOYGATE_CLEAN_TASK_NAME = 'deploygateClean' - public static final String CRASHLYTICS_TASK_NAME = 'crashlytics' - public static final String COCOAPODS_INSTALL_TASK_NAME = 'cocoapodsInstall' - public static final String COCOAPODS_UPDATE_TASK_NAME = 'cocoapodsUpdate' - public static final String COCOAPODS_BOOTSTRAP_TASK_NAME = 'cocoapodsBootstrap' - public static final String OCLINT_TASK_NAME = 'oclint' - public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' - public static final String CPD_TASK_NAME = 'cpd' - public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' - public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' - - - public static final String APPLEDOC_TASK_NAME = 'appledoc' - public static final String APPLEDOC_CLEAN_TASK_NAME = 'appledocClean' - - public static final COVERAGE_TASK_NAME = 'coverage' - public static final COVERAGE_CLEAN_TASK_NAME = 'coverageClean' - - - public static final String SDK_IPHONESIMULATOR = "iphonesimulator" - - - void apply(Project project) { - project.getPlugins().apply(BasePlugin.class); - - System.setProperty("java.awt.headless", "true"); - - configureExtensions(project) - configureClean(project) - configureBuild(project) - configureTest(project) - configureArchive(project) - configureHockeyKit(project) - configureKeychain(project) - configureInfoPlist(project) - configureProvisioning(project) - configureAppstore(project) - configureHockeyApp(project) - configureDeployGate(project) - configureCrashlytics(project) - configurePackage(project) - configureAppledoc(project) - configureCoverage(project) - configureCpd(project) - configureCocoapods(project) - configureCarthage(project) - configureOCLint(project) - configureSimulatorTasks(project) - configureProperties(project) - } - - - void configureProperties(Project project) { - - project.afterEvaluate { - - if (project.hasProperty('infoplist.bundleIdentifier')) { - project.infoplist.bundleIdentifier = project['infoplist.bundleIdentifier'] - } - if (project.hasProperty('infoplist.bundleIdentifierSuffix')) { - project.infoplist.bundleIdentifierSuffix = project['infoplist.bundleIdentifierSuffix'] - } - if (project.hasProperty('infoplist.bundleDisplayName')) { - project.infoplist.bundleDisplayName = project['infoplist.bundleDisplayName'] - } - if (project.hasProperty('infoplist.bundleDisplayNameSuffix')) { - project.infoplist.bundleDisplayNameSuffix = project['infoplist.bundleDisplayNameSuffix'] - } - - if (project.hasProperty('infoplist.version')) { - project.infoplist.version = project['infoplist.version'] - } - if (project.hasProperty('infoplist.versionPrefix')) { - project.infoplist.versionPrefix = project['infoplist.versionPrefix'] - } - if (project.hasProperty('infoplist.versionSuffix')) { - project.infoplist.versionSuffix = project['infoplist.versionSuffix'] - } - - - if (project.hasProperty('infoplist.shortVersionString')) { - project.infoplist.shortVersionString = project['infoplist.shortVersionString'] - } - if (project.hasProperty('infoplist.shortVersionStringSuffix')) { - project.infoplist.shortVersionStringSuffix = project['infoplist.shortVersionStringSuffix'] - } - if (project.hasProperty('infoplist.shortVersionStringPrefix')) { - project.infoplist.shortVersionStringPrefix = project['infoplist.shortVersionStringPrefix'] - } - - if (project.hasProperty('infoplist.iconPath')) { - project.infoplist.iconPath = project['infoplist.iconPath'] - } - - if (project.hasProperty('xcodebuild.scheme')) { - project.xcodebuild.scheme = project['xcodebuild.scheme'] - } - if (project.hasProperty('xcodebuild.infoPlist')) { - project.xcodebuild.infoPlist = project['xcodebuild.infoPlist'] - } - if (project.hasProperty('xcodebuild.configuration')) { - project.xcodebuild.configuration = project['xcodebuild.configuration'] - } - if (project.hasProperty('xcodebuild.sdk')) { - project.xcodebuild.sdk = project['xcodebuild.sdk'] - } - if (project.hasProperty('xcodebuild.target')) { - project.xcodebuild.target = project['xcodebuild.target'] - } - if (project.hasProperty('xcodebuild.dstRoot')) { - project.xcodebuild.dstRoot = project['xcodebuild.dstRoot'] - } - if (project.hasProperty('xcodebuild.objRoot')) { - project.xcodebuild.objRoot = project['xcodebuild.objRoot'] - } - if (project.hasProperty('xcodebuild.symRoot')) { - project.xcodebuild.symRoot = project['xcodebuild.symRoot'] - } - if (project.hasProperty('xcodebuild.sharedPrecompsDir')) { - project.xcodebuild.sharedPrecompsDir = project['xcodebuild.sharedPrecompsDir'] - } - if (project.hasProperty('xcodebuild.sourceDirectory')) { - project.xcodebuild.sourceDirectory = project['xcodebuild.sourceDirectory'] - } - - if (project.hasProperty('xcodebuild.signing.identity')) { - project.xcodebuild.signing.identity = project['xcodebuild.signing.identity'] - } - if (project.hasProperty('xcodebuild.signing.certificateURI')) { - project.xcodebuild.signing.certificateURI = project['xcodebuild.signing.certificateURI'] - } - if (project.hasProperty('xcodebuild.signing.certificatePassword')) { - project.xcodebuild.signing.certificatePassword = project['xcodebuild.signing.certificatePassword'] - } - if (project.hasProperty('xcodebuild.signing.mobileProvisionURI')) { - project.xcodebuild.signing.mobileProvisionURI = project['xcodebuild.signing.mobileProvisionURI'] - } - if (project.hasProperty('xcodebuild.signing.keychain')) { - project.xcodebuild.signing.keychain = project['xcodebuild.signing.keychain'] - } - if (project.hasProperty('xcodebuild.signing.keychainPassword')) { - project.xcodebuild.signing.keychainPassword = project['signing.keychainPassword'] - } - if (project.hasProperty('xcodebuild.signing.timeout')) { - project.xcodebuild.signing.timeout = project['signing.timeout'] - } - - if (project.hasProperty('xcodebuild.additionalParameters')) { - project.xcodebuild.additionalParameters = project['xcodebuild.additionalParameters'] - } - if (project.hasProperty('xcodebuild.bundleNameSuffix')) { - project.xcodebuild.bundleNameSuffix = project['xcodebuild.bundleNameSuffix'] - } - if (project.hasProperty('xcodebuild.arch')) { - project.xcodebuild.arch = project['xcodebuild.arch'] - } - if (project.hasProperty('xcodebuild.environment')) { - project.xcodebuild.environment = project['xcodebuild.environment'] - } - if (project.hasProperty('xcodebuild.version')) { - project.xcodebuild.version = project['xcodebuild.version'] - } - if (project.hasProperty('xcodebuild.ipaFileName')) { - project.xcodebuild.ipaFileName = project['xcodebuild.ipaFileName'] - } - if (project.hasProperty('xcodebuild.destination')) { - project.xcodebuild.destination = project['xcodebuild.destination'] - } - - if (project.hasProperty('hockeykit.displayName')) { - project.hockeykit.displayName = project['hockeykit.displayName'] - } - if (project.hasProperty('hockeykit.versionDirectoryName')) { - project.hockeykit.versionDirectoryName = project['hockeykit.versionDirectoryName'] - } - if (project.hasProperty('hockeykit.outputDirectory')) { - project.hockeykit.outputDirectory = project['hockeykit.outputDirectory'] - } - if (project.hasProperty('hockeykit.notes')) { - project.hockeykit.notes = project['hockeykit.notes'] - } - - - if (project.hasProperty('hockeyapp.apiToken')) { - project.hockeyapp.apiToken = project['hockeyapp.apiToken'] - } - if (project.hasProperty('hockeyapp.appID')) { - project.hockeyapp.appID = project['hockeyapp.appID'] - } - if (project.hasProperty('hockeyapp.notes')) { - project.hockeyapp.notes = project['hockeyapp.notes'] - } - if (project.hasProperty('hockeyapp.status')) { - project.hockeyapp.status = project['hockeyapp.status'] - } - if (project.hasProperty('hockeyapp.notify')) { - project.hockeyapp.notify = project['hockeyapp.notify'] - } - if (project.hasProperty('hockeyapp.notesType')) { - project.hockeyapp.notesType = project['hockeyapp.notesType'] - } - if (project.hasProperty('hockeyapp.teams')) { - project.hockeyapp.teams = project['hockeyapp.teams'] - } - if (project.hasProperty('hockeyapp.tags')) { - project.hockeyapp.tags = project['hockeyapp.tags'] - } - if (project.hasProperty('hockeyapp.releaseType')) { - project.hockeyapp.releaseType = project['hockeyapp.releaseType'] - } - if (project.hasProperty('hockeyapp.privatePage')) { - project.hockeyapp.privatePage = project['hockeyapp.privatePage'] - } - if (project.hasProperty('hockeyapp.commitSha')) { - project.hockeyapp.commitSha = project['hockeyapp.commitSha'] - } - if (project.hasProperty('hockeyapp.buildServerUrl')) { - project.hockeyapp.buildServerUrl = project['hockeyapp.buildServerUrl'] - } - if (project.hasProperty('hockeyapp.repositoryUrl')) { - project.hockeyapp.repositoryUrl = project['hockeyapp.repositoryUrl'] - } - - if (project.hasProperty('deploygate.outputDirectory')) { - project.deploygate.outputDirectory = project['deploygate.outputDirectory'] - } - - if (project.hasProperty('deploygate.apiToken')) { - project.deploygate.apiToken = project['deploygate.apiToken'] - } - if (project.hasProperty('deploygate.userName')) { - project.deploygate.userName = project['deploygate.userName'] - } - if (project.hasProperty('deploygate.message')) { - project.deploygate.message = project['deploygate.message'] - } - - if (project.hasProperty('crashlytics.submitCommand')) { - project.crashlytics.submitCommand = project['crashlytics.submitCommand'] - } - if (project.hasProperty('crashlytics.apiKey')) { - project.crashlytics.apiKey = project['crashlytics.apiKey'] - } - if (project.hasProperty('crashlytics.buildSecret')) { - project.crashlytics.buildSecret = project['crashlytics.buildSecret'] - } - if (project.hasProperty('crashlytics.emails')) { - project.crashlytics.emails = project['crashlytics.emails'] - } - if (project.hasProperty('crashlytics.groupAliases')) { - project.crashlytics.groupAliases = project['crashlytics.groupAliases'] - } - if (project.hasProperty('crashlytics.notesPath')) { - project.crashlytics.notesPath = project['crashlytics.notesPath'] - } - if (project.hasProperty('crashlytics.notifications')) { - project.crashlytics.notifications = project['crashlytics.notifications'] - } - - if (project.hasProperty('coverage.outputFormat')) { - project.coverage.outputFormat = project['coverage.outputFormat'] - } - if (project.hasProperty('coverage.exclude')) { - project.coverage.exclude = project['coverage.exclude'] - } - - if (project.hasProperty('appstore.username')) { - project.appstore.username = project['appstore.username'] - } - if (project.hasProperty('appstore.password')) { - project.appstore.password = project['appstore.password'] - } - - - if (project.hasProperty('oclint.reportType')) { - project.oclint.reportType = project['oclint.reportType']; - } - if (project.hasProperty('oclint.rules')) { - project.oclint.rules = project['oclint.rules']; - } - if (project.hasProperty('oclint.disableRules')) { - project.oclint.disableRules = project['oclint.disableRules']; - } - if (project.hasProperty('oclint.excludes')) { - project.oclint.excludes = project['oclint.excludes']; - } - if (project.hasProperty('oclint.maxPriority1')) { - project.oclint.maxPriority1 = project['oclint.maxPriority1']; - } - if (project.hasProperty('oclint.maxPriority2')) { - project.oclint.maxPriority2 = project['oclint.maxPriority2']; - } - if (project.hasProperty('oclint.maxPriority3')) { - project.oclint.maxPriority3 = project['oclint.maxPriority3']; - } - - - Task testTask = (Test) project.getTasks().findByPath(JavaPlugin.TEST_TASK_NAME) - if (testTask == null) { - testTask = project.getTasks().create(JavaPlugin.TEST_TASK_NAME) - } - testTask.dependsOn(XCODE_TEST_TASK_NAME) - - - configureCarthageDependencies(project) - configureCocoapodsDependencies(project) - configureTestRunDependencies(project) - } - - } - - - void configureExtensions(Project project) { - project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) - project.extensions.create("infoplist", InfoPlistExtension) - project.extensions.create("hockeykit", HockeyKitPluginExtension, project) - project.extensions.create("appstore", AppstorePluginExtension, project) - project.extensions.create("hockeyapp", HockeyAppPluginExtension, project) - project.extensions.create("deploygate", DeployGatePluginExtension, project) - project.extensions.create("crashlytics", CrashlyticsPluginExtension, project) - project.extensions.create("coverage", CoveragePluginExtension, project) - project.extensions.create("oclint", OCLintPluginExtension, project) - } - - - private void configureTestRunDependencies(Project project) { - for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { - if (xcodeTestRunTask.runOnDevice()) { - xcodeTestRunTask.dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - } - } - } - - private void configureBuild(Project project) { - XcodeBuildTask xcodebuildTask = project.getTasks().create(XCODE_BUILD_TASK_NAME, XcodeBuildTask.class); - xcodebuildTask.setGroup(XCODE_GROUP_NAME); - - XcodeConfigTask configTask = project.getTasks().create(XCODE_CONFIG_TASK_NAME, XcodeConfigTask.class); - configTask.setGroup(XCODE_GROUP_NAME); - - project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(xcodebuildTask); - } - - - private void configureClean(Project project) { - XcodeBuildCleanTask xcodeBuildCleanTask = project.getTasks().create(XCODE_CLEAN_TASK_NAME, XcodeBuildCleanTask.class); - xcodeBuildCleanTask.setGroup(XCODE_GROUP_NAME); - - project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(xcodeBuildCleanTask); - } - - private void configureArchive(Project project) { - if (project.xcodebuild.type == Type.tvOS - || project.xcodebuild.type == Type.iOS) { - PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.tasks.create( - PrepareXcodeArchivingTask.NAME, - PrepareXcodeArchivingTask.class) - prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) - - XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.tasks.create( - XcodeBuildArchiveTaskIosAndTvOS.NAME, - XcodeBuildArchiveTaskIosAndTvOS.class) - archiveTask.setGroup(XCODE_GROUP_NAME) - } else { - XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); - xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); - } - - //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); - } - - private void configureSimulatorTasks(Project project) { - project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_START_TASK_NAME, type: SimulatorStartTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_RUN_APP_TASK_NAME, type: SimulatorRunAppTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_INSTALL_APP_TASK_NAME, type: SimulatorInstallAppTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_KILL_TASK_NAME, type: SimulatorKillTask, group: SIMULATORS_LIST_TASK_NAME) - } - - private void configureHockeyKit(Project project) { - project.task(HOCKEYKIT_MANIFEST_TASK_NAME, type: HockeyKitManifestTask, group: HOCKEYKIT_GROUP_NAME) - HockeyKitArchiveTask hockeyKitArchiveTask = project.task(HOCKEYKIT_ARCHIVE_TASK_NAME, type: HockeyKitArchiveTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_NOTES_TASK_NAME, type: HockeyKitReleaseNotesTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_IMAGE_TASK_NAME, type: HockeyKitImageTask, group: HOCKEYKIT_GROUP_NAME) - project.task(HOCKEYKIT_CLEAN_TASK_NAME, type: HockeyKitCleanTask, group: HOCKEYKIT_GROUP_NAME) - - DefaultTask hockeykitTask = project.task(HOCKEYKIT_TASK_NAME, type: DefaultTask, description: "Creates a build that can be deployed on a hockeykit Server", group: HOCKEYKIT_GROUP_NAME); - hockeykitTask.dependsOn(HOCKEYKIT_ARCHIVE_TASK_NAME, HOCKEYKIT_MANIFEST_TASK_NAME, HOCKEYKIT_IMAGE_TASK_NAME, HOCKEYKIT_NOTES_TASK_NAME) - } - - private void configureKeychain(Project project) { - project.task(KEYCHAIN_CREATE_TASK_NAME, type: KeychainCreateTask, group: XCODE_GROUP_NAME) - project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) - project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) - } - - private void configureTest(Project project) { - project.task(XCODE_TEST_TASK_NAME, type: XcodeTestTask, group: XCODE_GROUP_NAME) - project.task(XCODE_BUILD_FOR_TEST_TASK_NAME, type: XcodeBuildForTestTask, group: XCODE_GROUP_NAME) - project.task(XCODE_TEST_RUN_TASK_NAME, type: XcodeTestRunTask, group: XCODE_GROUP_NAME) - - } - - private configureInfoPlist(Project project) { - project.task(INFOPLIST_MODIFY_TASK_NAME, type: InfoPlistModifyTask, group: XCODE_GROUP_NAME) - } - - private configureProvisioning(Project project) { - project.task(PROVISIONING_INSTALL_TASK_NAME, type: ProvisioningInstallTask, group: XCODE_GROUP_NAME) - project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) - } - - private configurePackage(Project project) { - PackageTask packageTask = project.task(PACKAGE_TASK_NAME, type: PackageTask, group: XCODE_GROUP_NAME) - - - project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) - - //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) + private static Logger logger = LoggerFactory.getLogger(XcodePlugin.class) + + public static final String XCODE_GROUP_NAME = "Xcode" + public static final String HOCKEYKIT_GROUP_NAME = "HockeyKit" + public static final String HOCKEYAPP_GROUP_NAME = "HockeyApp" + public static final String APPSTORE_GROUP_NAME = "AppStore" + public static final String DEPLOYGATE_GROUP_NAME = "DeployGate" + public static final String CRASHLYTICS_GROUP_NAME = "Crashlytics" + public static final String APPLE_DOC_GROUP_NAME = "Appledoc" + public static final String COVERAGE_GROUP_NAME = "Coverage" + public static final String COCOAPODS_GROUP_NAME = "Cocoapods" + public static final String CARTHAGE_GROUP_NAME = "Carthage" + public static final String SIMULATORS_GROUP_NAME = "Simulators" + public static final String ANALYTICS_GROUP_NAME = "Analytics" + + + public static final String XCODE_TEST_TASK_NAME = "xcodetest" + public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" + public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" + public static final String ARCHIVE_TASK_NAME = "archive" + public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" + public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" + public static final String SIMULATORS_CLEAN_TASK_NAME = "simulatorsClean" + public static final String SIMULATORS_START_TASK_NAME = "simulatorStart" + public static final String SIMULATORS_INSTALL_APP_TASK_NAME = "simulatorInstallApp" + public static final String SIMULATORS_RUN_APP_TASK_NAME = "simulatorRunApp" + public static final String SIMULATORS_KILL_TASK_NAME = "simulatorKill" + public static final String XCODE_BUILD_TASK_NAME = "xcodebuild" + public static final String XCODE_CLEAN_TASK_NAME = "xcodebuildClean" + public static final String XCODE_CONFIG_TASK_NAME = "xcodebuildConfig" + public static final String HOCKEYKIT_MANIFEST_TASK_NAME = "hockeykitManifest" + public static final String HOCKEYKIT_ARCHIVE_TASK_NAME = "hockeykitArchive" + public static final String HOCKEYKIT_NOTES_TASK_NAME = "hockeykitNotes" + public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" + public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" + public static final String HOCKEYKIT_TASK_NAME = "hockeykit" + public static final String KEYCHAIN_CREATE_TASK_NAME = "keychainCreate" + public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" + public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" + public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' + public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' + public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' + public static final String PACKAGE_TASK_NAME = 'package' + public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' + public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' + public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' + public static final String HOCKEYAPP_CLEAN_TASK_NAME = 'hockeyappClean' + public static final String HOCKEYAPP_TASK_NAME = 'hockeyapp' + public static final String DEPLOYGATE_TASK_NAME = 'deploygate' + public static final String DEPLOYGATE_CLEAN_TASK_NAME = 'deploygateClean' + public static final String CRASHLYTICS_TASK_NAME = 'crashlytics' + public static final String COCOAPODS_INSTALL_TASK_NAME = 'cocoapodsInstall' + public static final String COCOAPODS_UPDATE_TASK_NAME = 'cocoapodsUpdate' + public static final String COCOAPODS_BOOTSTRAP_TASK_NAME = 'cocoapodsBootstrap' + public static final String OCLINT_TASK_NAME = 'oclint' + public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' + public static final String CPD_TASK_NAME = 'cpd' + public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' + public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' + + + public static final String APPLEDOC_TASK_NAME = 'appledoc' + public static final String APPLEDOC_CLEAN_TASK_NAME = 'appledocClean' + + public static final COVERAGE_TASK_NAME = 'coverage' + public static final COVERAGE_CLEAN_TASK_NAME = 'coverageClean' + + + public static final String SDK_IPHONESIMULATOR = "iphonesimulator" + + + void apply(Project project) { + project.getPlugins().apply(BasePlugin.class); + + System.setProperty("java.awt.headless", "true"); + + configureExtensions(project) + configureClean(project) + configureBuild(project) + configureTest(project) + configureArchive(project) + configureHockeyKit(project) + configureKeychain(project) + configureInfoPlist(project) + configureProvisioning(project) + configureAppstore(project) + configureHockeyApp(project) + configureDeployGate(project) + configureCrashlytics(project) + configurePackage(project) + configureAppledoc(project) + configureCoverage(project) + configureCpd(project) + configureCocoapods(project) + configureCarthage(project) + configureOCLint(project) + configureSimulatorTasks(project) + configureProperties(project) + } + + + void configureProperties(Project project) { + + project.afterEvaluate { + + if (project.hasProperty('infoplist.bundleIdentifier')) { + project.infoplist.bundleIdentifier = project['infoplist.bundleIdentifier'] + } + if (project.hasProperty('infoplist.bundleIdentifierSuffix')) { + project.infoplist.bundleIdentifierSuffix = project['infoplist.bundleIdentifierSuffix'] + } + if (project.hasProperty('infoplist.bundleDisplayName')) { + project.infoplist.bundleDisplayName = project['infoplist.bundleDisplayName'] + } + if (project.hasProperty('infoplist.bundleDisplayNameSuffix')) { + project.infoplist.bundleDisplayNameSuffix = project['infoplist.bundleDisplayNameSuffix'] + } + + if (project.hasProperty('infoplist.version')) { + project.infoplist.version = project['infoplist.version'] + } + if (project.hasProperty('infoplist.versionPrefix')) { + project.infoplist.versionPrefix = project['infoplist.versionPrefix'] + } + if (project.hasProperty('infoplist.versionSuffix')) { + project.infoplist.versionSuffix = project['infoplist.versionSuffix'] + } + + + if (project.hasProperty('infoplist.shortVersionString')) { + project.infoplist.shortVersionString = project['infoplist.shortVersionString'] + } + if (project.hasProperty('infoplist.shortVersionStringSuffix')) { + project.infoplist.shortVersionStringSuffix = project['infoplist.shortVersionStringSuffix'] + } + if (project.hasProperty('infoplist.shortVersionStringPrefix')) { + project.infoplist.shortVersionStringPrefix = project['infoplist.shortVersionStringPrefix'] + } + + if (project.hasProperty('infoplist.iconPath')) { + project.infoplist.iconPath = project['infoplist.iconPath'] + } + + if (project.hasProperty('xcodebuild.scheme')) { + project.xcodebuild.scheme = project['xcodebuild.scheme'] + } + if (project.hasProperty('xcodebuild.infoPlist')) { + project.xcodebuild.infoPlist = project['xcodebuild.infoPlist'] + } + if (project.hasProperty('xcodebuild.configuration')) { + project.xcodebuild.configuration = project['xcodebuild.configuration'] + } + if (project.hasProperty('xcodebuild.sdk')) { + project.xcodebuild.sdk = project['xcodebuild.sdk'] + } + if (project.hasProperty('xcodebuild.target')) { + project.xcodebuild.target = project['xcodebuild.target'] + } + if (project.hasProperty('xcodebuild.dstRoot')) { + project.xcodebuild.dstRoot = project['xcodebuild.dstRoot'] + } + if (project.hasProperty('xcodebuild.objRoot')) { + project.xcodebuild.objRoot = project['xcodebuild.objRoot'] + } + if (project.hasProperty('xcodebuild.symRoot')) { + project.xcodebuild.symRoot = project['xcodebuild.symRoot'] + } + if (project.hasProperty('xcodebuild.sharedPrecompsDir')) { + project.xcodebuild.sharedPrecompsDir = project['xcodebuild.sharedPrecompsDir'] + } + if (project.hasProperty('xcodebuild.sourceDirectory')) { + project.xcodebuild.sourceDirectory = project['xcodebuild.sourceDirectory'] + } + + if (project.hasProperty('xcodebuild.signing.identity')) { + project.xcodebuild.signing.identity = project['xcodebuild.signing.identity'] + } + if (project.hasProperty('xcodebuild.signing.certificateURI')) { + project.xcodebuild.signing.certificateURI = project['xcodebuild.signing.certificateURI'] + } + if (project.hasProperty('xcodebuild.signing.certificatePassword')) { + project.xcodebuild.signing.certificatePassword = project['xcodebuild.signing.certificatePassword'] + } + if (project.hasProperty('xcodebuild.signing.mobileProvisionURI')) { + project.xcodebuild.signing.mobileProvisionURI = project['xcodebuild.signing.mobileProvisionURI'] + } + if (project.hasProperty('xcodebuild.signing.keychain')) { + project.xcodebuild.signing.keychain = project['xcodebuild.signing.keychain'] + } + if (project.hasProperty('xcodebuild.signing.keychainPassword')) { + project.xcodebuild.signing.keychainPassword = project['signing.keychainPassword'] + } + if (project.hasProperty('xcodebuild.signing.timeout')) { + project.xcodebuild.signing.timeout = project['signing.timeout'] + } + + if (project.hasProperty('xcodebuild.additionalParameters')) { + project.xcodebuild.additionalParameters = project['xcodebuild.additionalParameters'] + } + if (project.hasProperty('xcodebuild.bundleNameSuffix')) { + project.xcodebuild.bundleNameSuffix = project['xcodebuild.bundleNameSuffix'] + } + if (project.hasProperty('xcodebuild.arch')) { + project.xcodebuild.arch = project['xcodebuild.arch'] + } + if (project.hasProperty('xcodebuild.environment')) { + project.xcodebuild.environment = project['xcodebuild.environment'] + } + if (project.hasProperty('xcodebuild.version')) { + project.xcodebuild.version = project['xcodebuild.version'] + } + if (project.hasProperty('xcodebuild.ipaFileName')) { + project.xcodebuild.ipaFileName = project['xcodebuild.ipaFileName'] + } + if (project.hasProperty('xcodebuild.destination')) { + project.xcodebuild.destination = project['xcodebuild.destination'] + } + + if (project.hasProperty('hockeykit.displayName')) { + project.hockeykit.displayName = project['hockeykit.displayName'] + } + if (project.hasProperty('hockeykit.versionDirectoryName')) { + project.hockeykit.versionDirectoryName = project['hockeykit.versionDirectoryName'] + } + if (project.hasProperty('hockeykit.outputDirectory')) { + project.hockeykit.outputDirectory = project['hockeykit.outputDirectory'] + } + if (project.hasProperty('hockeykit.notes')) { + project.hockeykit.notes = project['hockeykit.notes'] + } + + + if (project.hasProperty('hockeyapp.apiToken')) { + project.hockeyapp.apiToken = project['hockeyapp.apiToken'] + } + if (project.hasProperty('hockeyapp.appID')) { + project.hockeyapp.appID = project['hockeyapp.appID'] + } + if (project.hasProperty('hockeyapp.notes')) { + project.hockeyapp.notes = project['hockeyapp.notes'] + } + if (project.hasProperty('hockeyapp.status')) { + project.hockeyapp.status = project['hockeyapp.status'] + } + if (project.hasProperty('hockeyapp.notify')) { + project.hockeyapp.notify = project['hockeyapp.notify'] + } + if (project.hasProperty('hockeyapp.notesType')) { + project.hockeyapp.notesType = project['hockeyapp.notesType'] + } + if (project.hasProperty('hockeyapp.teams')) { + project.hockeyapp.teams = project['hockeyapp.teams'] + } + if (project.hasProperty('hockeyapp.tags')) { + project.hockeyapp.tags = project['hockeyapp.tags'] + } + if (project.hasProperty('hockeyapp.releaseType')) { + project.hockeyapp.releaseType = project['hockeyapp.releaseType'] + } + if (project.hasProperty('hockeyapp.privatePage')) { + project.hockeyapp.privatePage = project['hockeyapp.privatePage'] + } + if (project.hasProperty('hockeyapp.commitSha')) { + project.hockeyapp.commitSha = project['hockeyapp.commitSha'] + } + if (project.hasProperty('hockeyapp.buildServerUrl')) { + project.hockeyapp.buildServerUrl = project['hockeyapp.buildServerUrl'] + } + if (project.hasProperty('hockeyapp.repositoryUrl')) { + project.hockeyapp.repositoryUrl = project['hockeyapp.repositoryUrl'] + } + + if (project.hasProperty('deploygate.outputDirectory')) { + project.deploygate.outputDirectory = project['deploygate.outputDirectory'] + } + + if (project.hasProperty('deploygate.apiToken')) { + project.deploygate.apiToken = project['deploygate.apiToken'] + } + if (project.hasProperty('deploygate.userName')) { + project.deploygate.userName = project['deploygate.userName'] + } + if (project.hasProperty('deploygate.message')) { + project.deploygate.message = project['deploygate.message'] + } + + if (project.hasProperty('crashlytics.submitCommand')) { + project.crashlytics.submitCommand = project['crashlytics.submitCommand'] + } + if (project.hasProperty('crashlytics.apiKey')) { + project.crashlytics.apiKey = project['crashlytics.apiKey'] + } + if (project.hasProperty('crashlytics.buildSecret')) { + project.crashlytics.buildSecret = project['crashlytics.buildSecret'] + } + if (project.hasProperty('crashlytics.emails')) { + project.crashlytics.emails = project['crashlytics.emails'] + } + if (project.hasProperty('crashlytics.groupAliases')) { + project.crashlytics.groupAliases = project['crashlytics.groupAliases'] + } + if (project.hasProperty('crashlytics.notesPath')) { + project.crashlytics.notesPath = project['crashlytics.notesPath'] + } + if (project.hasProperty('crashlytics.notifications')) { + project.crashlytics.notifications = project['crashlytics.notifications'] + } + + if (project.hasProperty('coverage.outputFormat')) { + project.coverage.outputFormat = project['coverage.outputFormat'] + } + if (project.hasProperty('coverage.exclude')) { + project.coverage.exclude = project['coverage.exclude'] + } + + if (project.hasProperty('appstore.username')) { + project.appstore.username = project['appstore.username'] + } + if (project.hasProperty('appstore.password')) { + project.appstore.password = project['appstore.password'] + } + + + if (project.hasProperty('oclint.reportType')) { + project.oclint.reportType = project['oclint.reportType']; + } + if (project.hasProperty('oclint.rules')) { + project.oclint.rules = project['oclint.rules']; + } + if (project.hasProperty('oclint.disableRules')) { + project.oclint.disableRules = project['oclint.disableRules']; + } + if (project.hasProperty('oclint.excludes')) { + project.oclint.excludes = project['oclint.excludes']; + } + if (project.hasProperty('oclint.maxPriority1')) { + project.oclint.maxPriority1 = project['oclint.maxPriority1']; + } + if (project.hasProperty('oclint.maxPriority2')) { + project.oclint.maxPriority2 = project['oclint.maxPriority2']; + } + if (project.hasProperty('oclint.maxPriority3')) { + project.oclint.maxPriority3 = project['oclint.maxPriority3']; + } + + + Task testTask = (Test) project.getTasks().findByPath(JavaPlugin.TEST_TASK_NAME) + if (testTask == null) { + testTask = project.getTasks().create(JavaPlugin.TEST_TASK_NAME) + } + testTask.dependsOn(XCODE_TEST_TASK_NAME) + + + configureCarthageDependencies(project) + configureCocoapodsDependencies(project) + configureTestRunDependencies(project) + } + + } + + + void configureExtensions(Project project) { + project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) + project.extensions.create("infoplist", InfoPlistExtension) + project.extensions.create("hockeykit", HockeyKitPluginExtension, project) + project.extensions.create("appstore", AppstorePluginExtension, project) + project.extensions.create("hockeyapp", HockeyAppPluginExtension, project) + project.extensions.create("deploygate", DeployGatePluginExtension, project) + project.extensions.create("crashlytics", CrashlyticsPluginExtension, project) + project.extensions.create("coverage", CoveragePluginExtension, project) + project.extensions.create("oclint", OCLintPluginExtension, project) + } + + + private void configureTestRunDependencies(Project project) { + for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { + if (xcodeTestRunTask.runOnDevice()) { + xcodeTestRunTask.dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) + } + } + } + + private void configureBuild(Project project) { + XcodeBuildTask xcodebuildTask = project.getTasks().create(XCODE_BUILD_TASK_NAME, XcodeBuildTask.class); + xcodebuildTask.setGroup(XCODE_GROUP_NAME); + + XcodeConfigTask configTask = project.getTasks().create(XCODE_CONFIG_TASK_NAME, XcodeConfigTask.class); + configTask.setGroup(XCODE_GROUP_NAME); + + project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(xcodebuildTask); + } + + + private void configureClean(Project project) { + XcodeBuildCleanTask xcodeBuildCleanTask = project.getTasks().create(XCODE_CLEAN_TASK_NAME, XcodeBuildCleanTask.class); + xcodeBuildCleanTask.setGroup(XCODE_GROUP_NAME); + + project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(xcodeBuildCleanTask); + } + + private void configureArchive(Project project) { + if (project.xcodebuild.type == Type.tvOS + || project.xcodebuild.type == Type.iOS) { + PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.tasks.create( + PrepareXcodeArchivingTask.NAME, + PrepareXcodeArchivingTask.class) + prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) + + XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.tasks.create( + XcodeBuildArchiveTaskIosAndTvOS.NAME, + XcodeBuildArchiveTaskIosAndTvOS.class) + archiveTask.setGroup(XCODE_GROUP_NAME) + } else { + XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); + xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); + } + + //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); + } - //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) + private void configureSimulatorTasks(Project project) { + project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_START_TASK_NAME, type: SimulatorStartTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_RUN_APP_TASK_NAME, type: SimulatorRunAppTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_INSTALL_APP_TASK_NAME, type: SimulatorInstallAppTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_KILL_TASK_NAME, type: SimulatorKillTask, group: SIMULATORS_LIST_TASK_NAME) + } + + private void configureHockeyKit(Project project) { + project.task(HOCKEYKIT_MANIFEST_TASK_NAME, type: HockeyKitManifestTask, group: HOCKEYKIT_GROUP_NAME) + HockeyKitArchiveTask hockeyKitArchiveTask = project.task(HOCKEYKIT_ARCHIVE_TASK_NAME, type: HockeyKitArchiveTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_NOTES_TASK_NAME, type: HockeyKitReleaseNotesTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_IMAGE_TASK_NAME, type: HockeyKitImageTask, group: HOCKEYKIT_GROUP_NAME) + project.task(HOCKEYKIT_CLEAN_TASK_NAME, type: HockeyKitCleanTask, group: HOCKEYKIT_GROUP_NAME) + + DefaultTask hockeykitTask = project.task(HOCKEYKIT_TASK_NAME, type: DefaultTask, description: "Creates a build that can be deployed on a hockeykit Server", group: HOCKEYKIT_GROUP_NAME); + hockeykitTask.dependsOn(HOCKEYKIT_ARCHIVE_TASK_NAME, HOCKEYKIT_MANIFEST_TASK_NAME, HOCKEYKIT_IMAGE_TASK_NAME, HOCKEYKIT_NOTES_TASK_NAME) + } + + private void configureKeychain(Project project) { + project.task(KEYCHAIN_CREATE_TASK_NAME, type: KeychainCreateTask, group: XCODE_GROUP_NAME) + project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) + project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) + } + + private void configureTest(Project project) { + project.task(XCODE_TEST_TASK_NAME, type: XcodeTestTask, group: XCODE_GROUP_NAME) + project.task(XCODE_BUILD_FOR_TEST_TASK_NAME, type: XcodeBuildForTestTask, group: XCODE_GROUP_NAME) + project.task(XCODE_TEST_RUN_TASK_NAME, type: XcodeTestRunTask, group: XCODE_GROUP_NAME) + + } + + private configureInfoPlist(Project project) { + project.task(INFOPLIST_MODIFY_TASK_NAME, type: InfoPlistModifyTask, group: XCODE_GROUP_NAME) + } + + private configureProvisioning(Project project) { + project.task(PROVISIONING_INSTALL_TASK_NAME, type: ProvisioningInstallTask, group: XCODE_GROUP_NAME) + project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) + } + + private configurePackage(Project project) { + PackageTask packageTask = project.task(PACKAGE_TASK_NAME, type: PackageTask, group: XCODE_GROUP_NAME) + + + project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) + + //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) + + //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) /* // disabled clean because of #115 packageTask.doLast { @@ -553,109 +553,109 @@ class XcodePlugin implements Plugin { keychainCleanupTask.clean() } */ - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) - packageTask.shouldRunAfter(xcodeBuildTask) - } + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) + packageTask.shouldRunAfter(xcodeBuildTask) + } - private configureAppstore(Project project) { - project.task(APPSTORE_UPLOAD_TASK_NAME, type: AppstoreUploadTask, group: APPSTORE_GROUP_NAME) - project.task(APPSTORE_VALIDATE_TASK_NAME, type: AppstoreValidateTask, group: APPSTORE_GROUP_NAME) - } + private configureAppstore(Project project) { + project.task(APPSTORE_UPLOAD_TASK_NAME, type: AppstoreUploadTask, group: APPSTORE_GROUP_NAME) + project.task(APPSTORE_VALIDATE_TASK_NAME, type: AppstoreValidateTask, group: APPSTORE_GROUP_NAME) + } - private void configureHockeyApp(Project project) { - project.task(HOCKEYAPP_CLEAN_TASK_NAME, type: HockeyAppCleanTask, group: HOCKEYAPP_GROUP_NAME) - project.task(HOCKEYAPP_TASK_NAME, type: HockeyAppUploadTask, group: HOCKEYAPP_GROUP_NAME) - } + private void configureHockeyApp(Project project) { + project.task(HOCKEYAPP_CLEAN_TASK_NAME, type: HockeyAppCleanTask, group: HOCKEYAPP_GROUP_NAME) + project.task(HOCKEYAPP_TASK_NAME, type: HockeyAppUploadTask, group: HOCKEYAPP_GROUP_NAME) + } - private void configureAppledoc(Project project) { - project.task(APPLEDOC_TASK_NAME, type: AppledocTask, group: APPLE_DOC_GROUP_NAME) - project.task(APPLEDOC_CLEAN_TASK_NAME, type: AppledocCleanTask, group: APPLE_DOC_GROUP_NAME) + private void configureAppledoc(Project project) { + project.task(APPLEDOC_TASK_NAME, type: AppledocTask, group: APPLE_DOC_GROUP_NAME) + project.task(APPLEDOC_CLEAN_TASK_NAME, type: AppledocCleanTask, group: APPLE_DOC_GROUP_NAME) - } + } - private void configureCoverage(Project project) { - project.task(COVERAGE_TASK_NAME, type: CoverageTask, group: COVERAGE_GROUP_NAME) - project.task(COVERAGE_CLEAN_TASK_NAME, type: CoverageCleanTask, group: COVERAGE_GROUP_NAME) + private void configureCoverage(Project project) { + project.task(COVERAGE_TASK_NAME, type: CoverageTask, group: COVERAGE_GROUP_NAME) + project.task(COVERAGE_CLEAN_TASK_NAME, type: CoverageCleanTask, group: COVERAGE_GROUP_NAME) - } + } - private void configureCpd(Project project) { - project.task(CPD_TASK_NAME, type: CpdTask, group: ANALYTICS_GROUP_NAME) - } + private void configureCpd(Project project) { + project.task(CPD_TASK_NAME, type: CpdTask, group: ANALYTICS_GROUP_NAME) + } - private void configureDeployGate(Project project) { - project.task(DEPLOYGATE_CLEAN_TASK_NAME, type: DeployGateCleanTask, group: DEPLOYGATE_GROUP_NAME) - project.task(DEPLOYGATE_TASK_NAME, type: DeployGateUploadTask, group: DEPLOYGATE_GROUP_NAME) - } + private void configureDeployGate(Project project) { + project.task(DEPLOYGATE_CLEAN_TASK_NAME, type: DeployGateCleanTask, group: DEPLOYGATE_GROUP_NAME) + project.task(DEPLOYGATE_TASK_NAME, type: DeployGateUploadTask, group: DEPLOYGATE_GROUP_NAME) + } - private void configureCrashlytics(Project project) { - project.task(CRASHLYTICS_TASK_NAME, type: CrashlyticsUploadTask, group: CRASHLYTICS_GROUP_NAME) - } + private void configureCrashlytics(Project project) { + project.task(CRASHLYTICS_TASK_NAME, type: CrashlyticsUploadTask, group: CRASHLYTICS_GROUP_NAME) + } - private void configureCocoapods(Project project) { - project.task(COCOAPODS_INSTALL_TASK_NAME, type: CocoapodsInstallTask, group: COCOAPODS_GROUP_NAME) - project.task(COCOAPODS_BOOTSTRAP_TASK_NAME, type: CocoapodsBootstrapTask, group: COCOAPODS_GROUP_NAME) - project.task(COCOAPODS_UPDATE_TASK_NAME, type: CocoapodsUpdateTask, group: COCOAPODS_GROUP_NAME) - } + private void configureCocoapods(Project project) { + project.task(COCOAPODS_INSTALL_TASK_NAME, type: CocoapodsInstallTask, group: COCOAPODS_GROUP_NAME) + project.task(COCOAPODS_BOOTSTRAP_TASK_NAME, type: CocoapodsBootstrapTask, group: COCOAPODS_GROUP_NAME) + project.task(COCOAPODS_UPDATE_TASK_NAME, type: CocoapodsUpdateTask, group: COCOAPODS_GROUP_NAME) + } - private configureCocoapodsDependencies(Project project) { - CocoapodsInstallTask cocoapodsInstallTask = project.getTasks().getByName(XcodePlugin.COCOAPODS_INSTALL_TASK_NAME) - if (cocoapodsInstallTask.hasPodfile()) { - addDependencyToBuild(project, cocoapodsInstallTask) - } - } + private configureCocoapodsDependencies(Project project) { + CocoapodsInstallTask cocoapodsInstallTask = project.getTasks().getByName(XcodePlugin.COCOAPODS_INSTALL_TASK_NAME) + if (cocoapodsInstallTask.hasPodfile()) { + addDependencyToBuild(project, cocoapodsInstallTask) + } + } - private void configureCarthage(Project project) { - project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) - project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) - } + private void configureCarthage(Project project) { + project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) + project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) + } - private configureCarthageDependencies(Project project) { - CarthageUpdateTask carthageUpdateTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME) - CarthageCleanTask carthageCleanTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_CLEAN_TASK_NAME) + private configureCarthageDependencies(Project project) { + CarthageUpdateTask carthageUpdateTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_UPDATE_TASK_NAME) + CarthageCleanTask carthageCleanTask = project.getTasks().getByName(XcodePlugin.CARTHAGE_CLEAN_TASK_NAME) - if (carthageUpdateTask.hasCartFile()) { - addDependencyToBuild(project, carthageUpdateTask) - project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(carthageCleanTask); - } - } + if (carthageUpdateTask.hasCartFile()) { + addDependencyToBuild(project, carthageUpdateTask) + project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME).dependsOn(carthageCleanTask); + } + } - private void configureOCLint(Project project) { - OCLintTask reportTask = project.task(OCLINT_REPORT_TASK_NAME, type: OCLintTask, group: ANALYTICS_GROUP_NAME) + private void configureOCLint(Project project) { + OCLintTask reportTask = project.task(OCLINT_REPORT_TASK_NAME, type: OCLintTask, group: ANALYTICS_GROUP_NAME) - Task ocLintTask = project.getTasks().create(OCLINT_TASK_NAME); - ocLintTask.group = ANALYTICS_GROUP_NAME - ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME - ocLintTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)) + Task ocLintTask = project.getTasks().create(OCLINT_TASK_NAME); + ocLintTask.group = ANALYTICS_GROUP_NAME + ocLintTask.description = "Runs: " + BasePlugin.CLEAN_TASK_NAME + " " + XCODE_BUILD_TASK_NAME + " " + OCLINT_REPORT_TASK_NAME + ocLintTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)) - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XcodePlugin.XCODE_BUILD_TASK_NAME) - reportTask.mustRunAfter(xcodeBuildTask) + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XcodePlugin.XCODE_BUILD_TASK_NAME) + reportTask.mustRunAfter(xcodeBuildTask) - ocLintTask.dependsOn(xcodeBuildTask) - ocLintTask.dependsOn(reportTask) + ocLintTask.dependsOn(xcodeBuildTask) + ocLintTask.dependsOn(reportTask) - } + } - private void addDependencyToBuild(Project project, Task task) { - logger.info("add task dependency for {}", task) + private void addDependencyToBuild(Project project, Task task) { + logger.info("add task dependency for {}", task) - for (Task buildTask : project.getTasks().withType(XcodeBuildTask.class)) { - buildTask.dependsOn(task) - } + for (Task buildTask : project.getTasks().withType(XcodeBuildTask.class)) { + buildTask.dependsOn(task) + } - for (Task testTask : project.getTasks().withType(XcodeTestTask.class)) { - testTask.dependsOn(task) - } + for (Task testTask : project.getTasks().withType(XcodeTestTask.class)) { + testTask.dependsOn(task) + } - for (Task buildForTestTask : project.getTasks().withType(XcodeBuildForTestTask.class)) { - logger.info("add task depencency for {}", buildForTestTask) - buildForTestTask.dependsOn(task) - } + for (Task buildForTestTask : project.getTasks().withType(XcodeBuildForTestTask.class)) { + logger.info("add task depencency for {}", buildForTestTask) + buildForTestTask.dependsOn(task) + } - } + } } From fbb12b79d828412acde5dd3b058cb3906da4b0dc Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 25 Apr 2018 10:06:13 +0100 Subject: [PATCH 043/121] Revert indentation changes --- .../org/openbakery/xcode/Xcodebuild.groovy | 684 +++++++++--------- 1 file changed, 342 insertions(+), 342 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index c3fd989c..114c55fd 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -5,346 +5,346 @@ import org.openbakery.output.OutputAppender class Xcodebuild { - CommandRunner commandRunner - - HashMap buildSettings = null - - File projectDirectory - String xcodePath - Xcode xcode - XcodebuildParameters parameters - List destinations - - public static final String ACTION_ARCHIVE = "archive" - public static final String ARGUMENT_SCHEME = "-scheme" - public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" - public static final String ARGUMENT_XCCONFIG = "-xcconfig" - - public Xcodebuild(File projectDirectory, CommandRunner commandRunner, Xcode xcode, XcodebuildParameters parameters, List destinations) { - this.projectDirectory = projectDirectory - this.commandRunner = commandRunner - this.xcode = xcode - this.parameters = parameters - this.destinations = destinations - } - - def validateParameters(OutputAppender outputAppender, Map environment) { - if (this.projectDirectory == null) { - throw new IllegalArgumentException("projectDirectory must not be null"); - } - - if (outputAppender == null) { - throw new IllegalArgumentException("outputAppender must not be null"); - } - - if (parameters.scheme == null && parameters.target == null) { - throw new IllegalArgumentException("No 'scheme' or 'target' specified, so do not know what to build"); - } - } - - public void archive(String scheme, - File outputPath, - File xcconfig) { - assert scheme != null - assert outputPath.exists() && outputPath.isDirectory() - assert xcconfig.exists() && !xcconfig.isDirectory() - - commandRunner.run("xcodebuild", - ACTION_ARCHIVE, - ARGUMENT_SCHEME, scheme, - ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, - ARGUMENT_XCCONFIG, xcconfig.absolutePath) - } - - def execute(OutputAppender outputAppender, Map environment) { - validateParameters(outputAppender, environment) - def commandList = [] - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addDestinationSettingsForBuild(commandList) - - commandRunner.run(projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def commandListForTest(OutputAppender outputAppender, Map environment) { - validateParameters(outputAppender, environment) - def commandList = [] - commandList << 'script' << '-q' << '/dev/null' - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addDestinationSettingsForTest(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addCoverageSettings(commandList) - return commandList - } - - def executeTest(OutputAppender outputAppender, Map environment) { - def commandList = commandListForTest(outputAppender, environment) - commandList << "test" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def executeBuildForTesting(OutputAppender outputAppender, Map environment) { - def commandList = commandListForTest(outputAppender, environment) - commandList << "build-for-testing" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - def executeTestWithoutBuilding(OutputAppender outputAppender, Map environment) { - - parameters.xctestrun.each { - def commandList = [] - commandList << 'script' << '-q' << '/dev/null' - commandList << xcode.xcodebuild - addDestinationSettingsForTest(commandList) - commandList.add("-derivedDataPath") - commandList.add(parameters.derivedDataPath.absolutePath) - addAdditionalParameters(commandList) - addCoverageSettings(commandList) - - commandList << "-xctestrun" << it.absolutePath - commandList << "test-without-building" - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - - - } - - } - - def executeArchive(OutputAppender outputAppender, Map environment, String archivePath) { - validateParameters(outputAppender, environment) - def commandList = [] - addBuildSettings(commandList) - addDisableCodeSigning(commandList) - addAdditionalParameters(commandList) - addBuildPath(commandList) - addDestinationSettingsForBuild(commandList) - commandList << "archive" - commandList << '-archivePath' - commandList << archivePath - commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) - } - - - def addBuildSettings(ArrayList commandList) { - - commandList << xcode.xcodebuild - - if (parameters.scheme) { - commandList.add("-scheme"); - commandList.add(parameters.scheme); - - if (parameters.workspace != null) { - commandList.add("-workspace") - commandList.add(parameters.workspace) - } - - if (parameters.configuration != null) { - commandList.add("-configuration") - commandList.add(parameters.configuration) - } - - - } else { - commandList.add("-configuration") - commandList.add(parameters.configuration) - - if (parameters.type == Type.macOS) { - commandList.add("-sdk") - commandList.add("macosx") - } - - commandList.add("-target") - commandList.add(parameters.target) - } - - if (parameters.bitcode) { - commandList.add('OTHER_CFLAGS="-fembed-bitcode"') - commandList.add('BITCODE_GENERATION_MODE=bitcode') - } - } - - def addDisableCodeSigning(ArrayList commandList) { - if (parameters.type != Type.macOS && parameters.simulator) { - // if it is a simulator build then do not add the parameters below - return - } - - commandList.add("CODE_SIGN_IDENTITY=") - commandList.add("CODE_SIGNING_REQUIRED=NO") - //commandList.add("CODE_SIGN_ENTITLEMENTS=") - //commandList.add("CODE_SIGNING_ALLOWED=NO") - } - - private boolean isSimulator() { - isSimulatorBuildOf(Type.iOS) || isSimulatorBuildOf(Type.tvOS) - } - - def addBuildPath(ArrayList commandList) { - if (parameters.scheme) { - // add this parameter only if a scheme is set - commandList.add("-derivedDataPath") - commandList.add(parameters.derivedDataPath.absolutePath) - } - commandList.add("DSTROOT=" + parameters.dstRoot.absolutePath) - commandList.add("OBJROOT=" + parameters.objRoot.absolutePath) - commandList.add("SYMROOT=" + parameters.symRoot.absolutePath) - commandList.add("SHARED_PRECOMPS_DIR=" + parameters.sharedPrecompsDir.absolutePath) - } - - def addAdditionalParameters(ArrayList commandList) { - if (parameters.arch != null) { - StringBuilder archs = new StringBuilder("ARCHS="); - for (String singleArch in parameters.arch) { - if (archs.length() > 7) { - archs.append(" "); - } - archs.append(singleArch); - } - commandList.add(archs.toString()); - } - - if (parameters.additionalParameters instanceof List) { - for (String value in parameters.additionalParameters) { - commandList.add(value) - } - } else { - if (parameters.additionalParameters != null) { - commandList.add(parameters.additionalParameters) - } - } - } - - - def addDestinationSettingsForBuild(ArrayList commandList) { - if (isSimulator()) { - Destination destination = this.destinations.last() - commandList.add("-destination") - commandList.add(getDestinationCommandParameter(destination)) - } - if (parameters.type == Type.macOS) { - commandList.add("-destination") - commandList.add("platform=OS X,arch=x86_64") - } - } - - def addDestinationSettingsForTest(ArrayList commandList) { - switch (parameters.type) { - case Type.iOS: - case Type.tvOS: - this.destinations.each { destination -> - commandList.add("-destination") - commandList.add(getDestinationCommandParameter(destination)) - } - break; - - case Type.macOS: - commandList.add("-destination") - commandList.add("platform=OS X,arch=x86_64") - break; - - default: - break; - } - } - - void addCoverageSettings(ArrayList commandList) { - if (xcode.version.major < 7) { - commandList.add("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES") - commandList.add("GCC_GENERATE_TEST_COVERAGE_FILES=YES") - } else { - commandList.add("-enableCodeCoverage") - commandList.add("yes") - } - } - - - boolean isSimulatorBuildOf(Type expectedType) { - if (parameters.type != expectedType) { - return false - } - if (parameters.type != Type.macOS) { - // os x does not have a simulator - return parameters.simulator - } - return false - } - - protected String getDestinationCommandParameter(Destination destination) { - def destinationParameters = [] - - if (destination.platform != null) { - destinationParameters << "platform=" + destination.platform - } - if (destination.id != null) { - destinationParameters << "id=" + destination.id - } else { - if (destination.name != null) { - destinationParameters << "name=" + destination.name - } - /* - if (destination.arch != null && parameters.availableDestinations.platform.equals("OS X")) { - destinationParameters << "arch=" + destination.arch - } - - if (destination.os != null && parameters.availableDestinations.platform.equals("iOS Simulator")) { - destinationParameters << "OS=" + destination.os - } - */ - } - return destinationParameters.join(",") - } - - - String getToolchainDirectory() { - String buildSetting = getBuildSetting("TOOLCHAIN_DIR") - if (buildSetting != null) { - return buildSetting - } - return "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain" - } - - String getPlatformDirectory() { - return getBuildSetting("PLATFORM_DIR") - } - - String loadBuildSettings() { - def commandList = [xcode.xcodebuild, "clean", "-showBuildSettings"] - - if (parameters.scheme != null && parameters.workspace != null) { - commandList.add("-scheme"); - commandList.add(parameters.scheme) - commandList.add("-workspace") - commandList.add(parameters.workspace) - } - - return commandRunner.runWithResult(this.projectDirectory.absolutePath, commandList) - } - - private String getBuildSetting(String key) { - if (buildSettings == null) { - buildSettings = new HashMap<>() - String[] buildSettingsData = loadBuildSettings().split("\n") - for (line in buildSettingsData) { - int index = line.indexOf("=") - if (index > 0) { - String settingsKey = line.substring(0, index).trim() - String settingsValue = line.substring(index + 1, line.length()).trim() - buildSettings.put(settingsKey, settingsValue) - } - } - } - return buildSettings.get(key) - } - - @Override - public String toString() { - return "Xcodebuild{" + - "xcodePath='" + xcodePath + '\'' + - parameters + - '}' - } + CommandRunner commandRunner + + HashMap buildSettings = null + + File projectDirectory + String xcodePath + Xcode xcode + XcodebuildParameters parameters + List destinations + + public static final String ACTION_ARCHIVE = "archive" + public static final String ARGUMENT_SCHEME = "-scheme" + public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" + public static final String ARGUMENT_XCCONFIG = "-xcconfig" + + public Xcodebuild(File projectDirectory, CommandRunner commandRunner, Xcode xcode, XcodebuildParameters parameters, List destinations) { + this.projectDirectory = projectDirectory + this.commandRunner = commandRunner + this.xcode = xcode + this.parameters = parameters + this.destinations = destinations + } + + def validateParameters(OutputAppender outputAppender, Map environment) { + if (this.projectDirectory == null) { + throw new IllegalArgumentException("projectDirectory must not be null"); + } + + if (outputAppender == null) { + throw new IllegalArgumentException("outputAppender must not be null"); + } + + if (parameters.scheme == null && parameters.target == null) { + throw new IllegalArgumentException("No 'scheme' or 'target' specified, so do not know what to build"); + } + } + + public void archive(String scheme, + File outputPath, + File xcconfig) { + assert scheme != null + assert outputPath.exists() && outputPath.isDirectory() + assert xcconfig.exists() && !xcconfig.isDirectory() + + commandRunner.run("xcodebuild", + ACTION_ARCHIVE, + ARGUMENT_SCHEME, scheme, + ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, + ARGUMENT_XCCONFIG, xcconfig.absolutePath) + } + + def execute(OutputAppender outputAppender, Map environment) { + validateParameters(outputAppender, environment) + def commandList = [] + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addDestinationSettingsForBuild(commandList) + + commandRunner.run(projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def commandListForTest(OutputAppender outputAppender, Map environment) { + validateParameters(outputAppender, environment) + def commandList = [] + commandList << 'script' << '-q' << '/dev/null' + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addDestinationSettingsForTest(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addCoverageSettings(commandList) + return commandList + } + + def executeTest(OutputAppender outputAppender, Map environment) { + def commandList = commandListForTest(outputAppender, environment) + commandList << "test" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def executeBuildForTesting(OutputAppender outputAppender, Map environment) { + def commandList = commandListForTest(outputAppender, environment) + commandList << "build-for-testing" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + def executeTestWithoutBuilding(OutputAppender outputAppender, Map environment) { + + parameters.xctestrun.each { + def commandList = [] + commandList << 'script' << '-q' << '/dev/null' + commandList << xcode.xcodebuild + addDestinationSettingsForTest(commandList) + commandList.add("-derivedDataPath") + commandList.add(parameters.derivedDataPath.absolutePath) + addAdditionalParameters(commandList) + addCoverageSettings(commandList) + + commandList << "-xctestrun" << it.absolutePath + commandList << "test-without-building" + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + + + } + + } + + def executeArchive(OutputAppender outputAppender, Map environment, String archivePath) { + validateParameters(outputAppender, environment) + def commandList = [] + addBuildSettings(commandList) + addDisableCodeSigning(commandList) + addAdditionalParameters(commandList) + addBuildPath(commandList) + addDestinationSettingsForBuild(commandList) + commandList << "archive" + commandList << '-archivePath' + commandList << archivePath + commandRunner.run(this.projectDirectory.absolutePath, commandList, environment, outputAppender) + } + + + def addBuildSettings(ArrayList commandList) { + + commandList << xcode.xcodebuild + + if (parameters.scheme) { + commandList.add("-scheme"); + commandList.add(parameters.scheme); + + if (parameters.workspace != null) { + commandList.add("-workspace") + commandList.add(parameters.workspace) + } + + if (parameters.configuration != null) { + commandList.add("-configuration") + commandList.add(parameters.configuration) + } + + + } else { + commandList.add("-configuration") + commandList.add(parameters.configuration) + + if (parameters.type == Type.macOS) { + commandList.add("-sdk") + commandList.add("macosx") + } + + commandList.add("-target") + commandList.add(parameters.target) + } + + if (parameters.bitcode) { + commandList.add('OTHER_CFLAGS="-fembed-bitcode"') + commandList.add('BITCODE_GENERATION_MODE=bitcode') + } + } + + def addDisableCodeSigning(ArrayList commandList) { + if (parameters.type != Type.macOS && parameters.simulator) { + // if it is a simulator build then do not add the parameters below + return + } + + commandList.add("CODE_SIGN_IDENTITY=") + commandList.add("CODE_SIGNING_REQUIRED=NO") + //commandList.add("CODE_SIGN_ENTITLEMENTS=") + //commandList.add("CODE_SIGNING_ALLOWED=NO") + } + + private boolean isSimulator() { + isSimulatorBuildOf(Type.iOS) || isSimulatorBuildOf(Type.tvOS) + } + + def addBuildPath(ArrayList commandList) { + if (parameters.scheme) { + // add this parameter only if a scheme is set + commandList.add("-derivedDataPath") + commandList.add(parameters.derivedDataPath.absolutePath) + } + commandList.add("DSTROOT=" + parameters.dstRoot.absolutePath) + commandList.add("OBJROOT=" + parameters.objRoot.absolutePath) + commandList.add("SYMROOT=" + parameters.symRoot.absolutePath) + commandList.add("SHARED_PRECOMPS_DIR=" + parameters.sharedPrecompsDir.absolutePath) + } + + def addAdditionalParameters(ArrayList commandList) { + if (parameters.arch != null) { + StringBuilder archs = new StringBuilder("ARCHS="); + for (String singleArch in parameters.arch) { + if (archs.length() > 7) { + archs.append(" "); + } + archs.append(singleArch); + } + commandList.add(archs.toString()); + } + + if (parameters.additionalParameters instanceof List) { + for (String value in parameters.additionalParameters) { + commandList.add(value) + } + } else { + if (parameters.additionalParameters != null) { + commandList.add(parameters.additionalParameters) + } + } + } + + + def addDestinationSettingsForBuild(ArrayList commandList) { + if (isSimulator()) { + Destination destination = this.destinations.last() + commandList.add("-destination") + commandList.add(getDestinationCommandParameter(destination)) + } + if (parameters.type == Type.macOS) { + commandList.add("-destination") + commandList.add("platform=OS X,arch=x86_64") + } + } + + def addDestinationSettingsForTest(ArrayList commandList) { + switch (parameters.type) { + case Type.iOS: + case Type.tvOS: + this.destinations.each { destination -> + commandList.add("-destination") + commandList.add(getDestinationCommandParameter(destination)) + } + break; + + case Type.macOS: + commandList.add("-destination") + commandList.add("platform=OS X,arch=x86_64") + break; + + default: + break; + } + } + + void addCoverageSettings(ArrayList commandList) { + if (xcode.version.major < 7) { + commandList.add("GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES") + commandList.add("GCC_GENERATE_TEST_COVERAGE_FILES=YES") + } else { + commandList.add("-enableCodeCoverage") + commandList.add("yes") + } + } + + + boolean isSimulatorBuildOf(Type expectedType) { + if (parameters.type != expectedType) { + return false + } + if (parameters.type != Type.macOS) { + // os x does not have a simulator + return parameters.simulator + } + return false + } + + protected String getDestinationCommandParameter(Destination destination) { + def destinationParameters = [] + + if (destination.platform != null) { + destinationParameters << "platform=" + destination.platform + } + if (destination.id != null) { + destinationParameters << "id=" + destination.id + } else { + if (destination.name != null) { + destinationParameters << "name=" + destination.name + } + /* + if (destination.arch != null && parameters.availableDestinations.platform.equals("OS X")) { + destinationParameters << "arch=" + destination.arch + } + + if (destination.os != null && parameters.availableDestinations.platform.equals("iOS Simulator")) { + destinationParameters << "OS=" + destination.os + } + */ + } + return destinationParameters.join(",") + } + + + String getToolchainDirectory() { + String buildSetting = getBuildSetting("TOOLCHAIN_DIR") + if (buildSetting != null) { + return buildSetting + } + return "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain" + } + + String getPlatformDirectory() { + return getBuildSetting("PLATFORM_DIR") + } + + String loadBuildSettings() { + def commandList = [xcode.xcodebuild, "clean", "-showBuildSettings"] + + if (parameters.scheme != null && parameters.workspace != null) { + commandList.add("-scheme"); + commandList.add(parameters.scheme) + commandList.add("-workspace") + commandList.add(parameters.workspace) + } + + return commandRunner.runWithResult(this.projectDirectory.absolutePath, commandList) + } + + private String getBuildSetting(String key) { + if (buildSettings == null) { + buildSettings = new HashMap<>() + String[] buildSettingsData = loadBuildSettings().split("\n") + for (line in buildSettingsData) { + int index = line.indexOf("=") + if (index > 0) { + String settingsKey = line.substring(0, index).trim() + String settingsValue = line.substring(index + 1, line.length()).trim() + buildSettings.put(settingsKey, settingsValue) + } + } + } + return buildSettings.get(key) + } + + @Override + public String toString() { + return "Xcodebuild{" + + "xcodePath='" + xcodePath + '\'' + + parameters + + '}' + } } From 3c213fbd4b699da0e617f434b6a17b599c5c0a3b Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 25 Apr 2018 11:12:44 +0100 Subject: [PATCH 044/121] Re-enable compilestatis --- .../PrepareXcodeArchivingTask.groovy | 4 +-- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 27 +++++-------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 96db142f..e90d0215 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -13,8 +13,8 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader public static final String NAME = "prepareArchiving" + public static final String FILE_NAME = "archive.xcconfig" - private static final String FILE_NAME = "archive.xcconfig" private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" @@ -64,9 +64,9 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private void computeProvisioningFile(File file) { reader = new ProvisioningProfileReader(file, commandRunner) + append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) append(KEY_CODE_SIGN_IDENTITY, getCodeSignIdentity()) append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) - append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index b9c24d4a..ecccf890 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,25 +1,11 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.openbakery +import groovy.transform.CompileStatic import org.gradle.api.tasks.* import org.openbakery.util.PathHelper import org.openbakery.xcode.Xcodebuild -//@CompileStatic +@CompileStatic class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { public static final String NAME = "archive" @@ -42,13 +28,12 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input String getScheme() { - return project.xcodebuild.scheme + return getXcodeExtension().scheme } @OutputFile File getOutputTextFile() { - File file = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - return file + return new File(project.getBuildDir(), "xcodebuild-archive-output.txt") } @OutputDirectory @@ -61,7 +46,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @TaskAction private void archive() { - Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, + Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, @@ -69,7 +54,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { commandRunner.setOutputFile(getOutputTextFile()) - xcodebuild.archive(getScheme(), + xcodeBuild.archive(getScheme(), getOutputDirectory(), getXcConfigFile()) } From e7aa7c84e25d94a8bf08ed0b60093133175d037d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 25 Apr 2018 14:38:15 +0100 Subject: [PATCH 045/121] --wip-- [skip ci] --- .../codesign/ProvisioningProfileReader.groovy | 656 +++++++++--------- .../PrepareXcodeArchivingTask.groovy | 36 +- 2 files changed, 358 insertions(+), 334 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy index 2ab62d04..cc9cc7a5 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy @@ -31,357 +31,357 @@ import java.text.DateFormat class ProvisioningProfileReader { - enum EntitlementAction { - ADD, REPLACE, DELETE - } + enum EntitlementAction { + ADD, REPLACE, DELETE + } - public static final String APPLICATION_IDENTIFIER_PREFIX = '$(AppIdentifierPrefix)' - protected CommandRunner commandRunner - private PlistHelper plistHelper + public static final String APPLICATION_IDENTIFIER_PREFIX = '$(AppIdentifierPrefix)' + protected CommandRunner commandRunner + private PlistHelper plistHelper - private static Logger logger = LoggerFactory.getLogger(ProvisioningProfileReader.class) + private static Logger logger = LoggerFactory.getLogger(ProvisioningProfileReader.class) - XMLPropertyListConfiguration config + XMLPropertyListConfiguration config - private File provisioningProfile - private File provisioningPlist + private File provisioningProfile + private File provisioningPlist - ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner) { - this(provisioningProfile, commandRunner, new PlistHelper(commandRunner)) - } + ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner) { + this(provisioningProfile, commandRunner, new PlistHelper(commandRunner)) + } - ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner, PlistHelper plistHelper) { - super() + ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner, PlistHelper plistHelper) { + super() - logger.debug("load provisioningProfile: {}", provisioningProfile) - String text = load(provisioningProfile) - logger.debug("provisioningProfile content:\n{}\n--- END ---", text) - config = new XMLPropertyListConfiguration() - config.load(new StringReader(text)) + logger.debug("load provisioningProfile: {}", provisioningProfile) + String text = load(provisioningProfile) + logger.debug("provisioningProfile content:\n{}\n--- END ---", text) + config = new XMLPropertyListConfiguration() + config.load(new StringReader(text)) - this.commandRunner = commandRunner + this.commandRunner = commandRunner - this.plistHelper = plistHelper + this.plistHelper = plistHelper - checkExpired() - } + checkExpired() + } - static File getProvisionFileForIdentifier(String bundleIdentifier, List mobileProvisionFiles, CommandRunner commandRunner, PlistHelper plistHelper) { - def provisionFileMap = [:] + static File getProvisionFileForIdentifier(String bundleIdentifier, List mobileProvisionFiles, CommandRunner commandRunner, PlistHelper plistHelper) { + def provisionFileMap = [:] - for (File mobileProvisionFile : mobileProvisionFiles) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileProvisionFile, commandRunner, plistHelper) - provisionFileMap.put(reader.getApplicationIdentifier(), mobileProvisionFile) - } + for (File mobileProvisionFile : mobileProvisionFiles) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileProvisionFile, commandRunner, plistHelper) + provisionFileMap.put(reader.getApplicationIdentifier(), mobileProvisionFile) + } - logger.debug("provisionFileMap: {}", provisionFileMap) + logger.debug("provisionFileMap: {}", provisionFileMap) - for (entry in provisionFileMap) { - if (entry.key.equalsIgnoreCase(bundleIdentifier)) { - return entry.value - } - } + for (entry in provisionFileMap) { + if (entry.key.equalsIgnoreCase(bundleIdentifier)) { + return entry.value + } + } - // match wildcard - for (entry in provisionFileMap) { - if (entry.key.equals("*")) { - return entry.value - } + // match wildcard + for (entry in provisionFileMap) { + if (entry.key.equals("*")) { + return entry.value + } - if (entry.key.endsWith("*")) { - String key = entry.key[0..-2].toLowerCase() - if (bundleIdentifier.toLowerCase().startsWith(key)) { - return entry.value - } - } - } + if (entry.key.endsWith("*")) { + String key = entry.key[0..-2].toLowerCase() + if (bundleIdentifier.toLowerCase().startsWith(key)) { + return entry.value + } + } + } - logger.info("No provisioning profile found for bundle identifier {}", bundleIdentifier) - logger.info("Available bundle identifier are {}" + provisionFileMap.keySet()) + logger.info("No provisioning profile found for bundle identifier {}", bundleIdentifier) + logger.info("Available bundle identifier are {}" + provisionFileMap.keySet()) - return null - } + return null + } - String load(File provisioningProfile) { - this.provisioningProfile = provisioningProfile + String load(File provisioningProfile) { + this.provisioningProfile = provisioningProfile - if (!this.provisioningProfile.exists()) { - logger.warn("The specified provisioning profile does not exist: " + this.provisioningProfile.absolutePath) - return null - } + if (!this.provisioningProfile.exists()) { + logger.warn("The specified provisioning profile does not exist: " + this.provisioningProfile.absolutePath) + return null + } - StringBuffer result = new StringBuffer() - - boolean append = false - for (String line : this.provisioningProfile.text.split("\n")) { - if (line.startsWith("")) { - result.append("") - return result.toString() - } - - if (append) { - result.append(line) - result.append("\n") - } - - - } - return "" - } - - - boolean checkExpired() { - - Date expireDate = config.getProperty("ExpirationDate") - if (expireDate.before(new Date())) { - DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault()) - throw new IllegalArgumentException("The Provisioning Profile has expired on " + formatter.format(expireDate) ) - } - } - - - String getUUID() { - return config.getString("UUID") - } - - String getApplicationIdentifierPrefix() { - return config.getString("ApplicationIdentifierPrefix") - } - - String getTeamIdentifierPrefix() { - return config.getString("TeamIdentifier") - } - - String getTeamName() { - return config.getString("TeamName") - } - - String getName() { - return config.getString("Name") - } - - File getPlistFromProvisioningProfile() { - if (provisioningPlist == null) { - // unpack provisioning profile to plain plist - String basename = FilenameUtils.getBaseName(provisioningProfile.path) - // read temporary plist file - File tmpDir = new File(System.getProperty("java.io.tmpdir")) - provisioningPlist = new File(tmpDir, "provision_" + basename + ".plist") - provisioningPlist.deleteOnExit() - - try { - commandRunner.run(["security", - "cms", - "-D", - "-i", - provisioningProfile.getCanonicalPath(), - "-o", - provisioningPlist.absolutePath - ]) - } catch (CommandRunnerException ex) { - if (!provisioningPlist.exists()) { - throw new IllegalStateException("provisioning plist does not exist: " + provisioningPlist) - } - } - } - return provisioningPlist - } - - String getApplicationIdentifier() { - - String value - - if (this.provisioningProfile.path.endsWith(".mobileprovision")) { - value = config.getProperty("Entitlements.application-identifier") - } else { - value = plistHelper.getValueFromPlist(getPlistFromProvisioningProfile(), "Entitlements:com.apple.application-identifier") - } - - String prefix = getApplicationIdentifierPrefix() + "." - if (value.startsWith(prefix)) { - return value.substring(prefix.length()) - } - return value - } - - /* xcent is the archive entitlements */ - void extractEntitlements(File entitlementFile, String bundleIdentifier, List keychainAccessGroups, Configuration configuration) { - logger.info("extractEntitlements for " + bundleIdentifier) - File plistFromProvisioningProfile = getPlistFromProvisioningProfile() - String entitlements = commandRunner.runWithResult([ - "/usr/libexec/PlistBuddy", - "-x", - plistFromProvisioningProfile.absolutePath, - "-c", - "Print Entitlements"]) - - if (StringUtils.isEmpty(entitlements)) { - logger.debug("No entitlements found in {}", plistFromProvisioningProfile) - return - } - //String entitlements = plistHelper.commandForPlist(getPlistFromProvisioningProfile(), "Print Entitlements") - FileUtils.writeStringToFile(entitlementFile, entitlements.toString()) - - - - def applicationIdentifier = plistHelper.getValueFromPlist(entitlementFile, "application-identifier") - logger.info("applicationIdentifier from entitlements: {}", applicationIdentifier) - String bundleIdentifierPrefix = "" - if (applicationIdentifier != null) { - String[] tokens = applicationIdentifier.split("\\.") - for (int i=1; i 0) { - bundleIdentifierPrefix += "." - } - bundleIdentifierPrefix += tokens[i] - } - } - - if (!bundleIdentifier.startsWith(bundleIdentifierPrefix)) { - throw new IllegalStateException("In the provisioning profile a application identifier is specified with " + bundleIdentifierPrefix + " but the app uses a bundle identifier " + bundleIdentifier + " that does not match!") - } - - - String applicationIdentifierPrefix = getApplicationIdentifierPrefix() - String teamIdentifierPrefix = getTeamIdentifierPrefix() - if (teamIdentifierPrefix == null) { - teamIdentifierPrefix = applicationIdentifierPrefix - } - - - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "application-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "com.apple.application-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-kvstore-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-container-identifiers") - - - - - if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { - def modifiedKeychainAccessGroups = [] - keychainAccessGroups.each() { group -> - modifiedKeychainAccessGroups << group.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") - } - plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) - } else { - plistHelper.deleteValueFromPlist(entitlementFile, "keychain-access-groups") - } - - - // copy the missing values that are in configuration (xcent or signing.entitlments) to the entitlements for signing - enumerateMissingEntitlements(entitlementFile, configuration) { key, value, action -> - - if (value instanceof String) { - value = this.replaceVariables(value) - } else if (value instanceof List) { - value = this.replaceValuesInList((List)value) - } - - - - switch (action) { - case EntitlementAction.REPLACE: - logger.info("replace in entitlement: {} with {}", key, value) - plistHelper.setValueForPlist(entitlementFile, key, value) - break - case EntitlementAction.ADD: - logger.info("add to entitlement: {} with {}", key, value) - plistHelper.addValueForPlist(entitlementFile, key, value) - break - case EntitlementAction.DELETE: - logger.info("delete to entitlement: {}", key) - plistHelper.deleteValueFromPlist(entitlementFile, key) - break - } - } - - - if (logger.isDebugEnabled()) { - String entitlementsContent = FileUtils.readFileToString(entitlementFile) - logger.debug("entitlements content\n{}", entitlementsContent) - } - } - - private List replaceValuesInList(List list) { - def result = [] - for (Object item : list) { - if (item instanceof String) { - result << replaceVariables((String)item) - } else { - result << item - } - } - return result - } - - private String replaceVariables(String value) { - - if (value.startsWith(APPLICATION_IDENTIFIER_PREFIX)) { - return value.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") - } - return value - } - - private void enumerateMissingEntitlements(File entitlementFile, Configuration configuration, Closure closure) { - if (configuration == null) { - return - } - - Configuration entitlements = new ConfigurationFromPlist(entitlementFile) - SetreplaceKeys = configuration.getReplaceEntitlementsKeys() - - for (String key in configuration.getKeys()) { - Object value = configuration.get(key) //plistHelper.getValueFromPlist(xcent, key) - - if (!entitlements.containsKey(key)) { - closure(key, value, EntitlementAction.ADD) - } else if (replaceKeys.contains(key)) { - closure(key, value, EntitlementAction.REPLACE) - } - } - - for (String key in configuration.getDeleteEntitlementsKeys()) { - closure(key, null, EntitlementAction.DELETE) - } - - } - - private void setBundleIdentifierToEntitlementsForValue(File entitlementFile, String bundleIdentifier, String prefix, String value) { - def currentValue = plistHelper.getValueFromPlist(entitlementFile, value) - - if (currentValue == null) { - return - } - - if (currentValue instanceof List) { - def modifiedValues = [] - currentValue.each { item -> - if (item.toString().endsWith('*')) { - modifiedValues << prefix + "." + bundleIdentifier - } - } - plistHelper.setValueForPlist(entitlementFile, value, modifiedValues) - - } else { - if (currentValue.toString().endsWith('*')) { - plistHelper.setValueForPlist(entitlementFile, value, prefix + "." + bundleIdentifier) - } - } - } - - public boolean isAdHoc() { - def provisionedDevices = config.getList("ProvisionedDevices") - return !provisionedDevices.empty - } + StringBuffer result = new StringBuffer() + + boolean append = false + for (String line : this.provisioningProfile.text.split("\n")) { + if (line.startsWith("")) { + result.append("") + return result.toString() + } + + if (append) { + result.append(line) + result.append("\n") + } + + + } + return "" + } + + + boolean checkExpired() { + + Date expireDate = config.getProperty("ExpirationDate") + if (expireDate.before(new Date())) { + DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault()) + throw new IllegalArgumentException("The Provisioning Profile has expired on " + formatter.format(expireDate)) + } + } + + + String getUUID() { + return config.getString("UUID") + } + + String getApplicationIdentifierPrefix() { + return config.getString("ApplicationIdentifierPrefix") + } + + String getTeamIdentifierPrefix() { + return config.getString("TeamIdentifier") + } + + String getTeamName() { + return config.getString("TeamName") + } + + String getName() { + return config.getString("Name") + } + + File getPlistFromProvisioningProfile() { + if (provisioningPlist == null) { + // unpack provisioning profile to plain plist + String basename = FilenameUtils.getBaseName(provisioningProfile.path) + // read temporary plist file + File tmpDir = new File(System.getProperty("java.io.tmpdir")) + provisioningPlist = new File(tmpDir, "provision_" + basename + ".plist") + provisioningPlist.deleteOnExit() + + try { + commandRunner.run(["security", + "cms", + "-D", + "-i", + provisioningProfile.getCanonicalPath(), + "-o", + provisioningPlist.absolutePath + ]) + } catch (CommandRunnerException ex) { + if (!provisioningPlist.exists()) { + throw new IllegalStateException("provisioning plist does not exist: " + provisioningPlist) + } + } + } + return provisioningPlist + } + + String getApplicationIdentifier() { + + String value + + if (this.provisioningProfile.path.endsWith(".mobileprovision")) { + value = config.getProperty("Entitlements.application-identifier") + } else { + value = plistHelper.getValueFromPlist(getPlistFromProvisioningProfile(), "Entitlements:com.apple.application-identifier") + } + + String prefix = getApplicationIdentifierPrefix() + "." + if (value.startsWith(prefix)) { + return value.substring(prefix.length()) + } + return value + } + + /* xcent is the archive entitlements */ + + void extractEntitlements(File entitlementFile, String bundleIdentifier, List keychainAccessGroups, Configuration configuration) { + logger.info("extractEntitlements for " + bundleIdentifier) + File plistFromProvisioningProfile = getPlistFromProvisioningProfile() + String entitlements = commandRunner.runWithResult([ + "/usr/libexec/PlistBuddy", + "-x", + plistFromProvisioningProfile.absolutePath, + "-c", + "Print Entitlements"]) + + if (StringUtils.isEmpty(entitlements)) { + logger.debug("No entitlements found in {}", plistFromProvisioningProfile) + return + } + //String entitlements = plistHelper.commandForPlist(getPlistFromProvisioningProfile(), "Print Entitlements") + FileUtils.writeStringToFile(entitlementFile, entitlements.toString()) + + + + def applicationIdentifier = plistHelper.getValueFromPlist(entitlementFile, "application-identifier") + logger.info("applicationIdentifier from entitlements: {}", applicationIdentifier) + String bundleIdentifierPrefix = "" + if (applicationIdentifier != null) { + String[] tokens = applicationIdentifier.split("\\.") + for (int i = 1; i < tokens.length; i++) { + if (tokens[i] == "*") { + break + } + if (bundleIdentifierPrefix.length() > 0) { + bundleIdentifierPrefix += "." + } + bundleIdentifierPrefix += tokens[i] + } + } + + if (!bundleIdentifier.startsWith(bundleIdentifierPrefix)) { + throw new IllegalStateException("In the provisioning profile a application identifier is specified with " + bundleIdentifierPrefix + " but the app uses a bundle identifier " + bundleIdentifier + " that does not match!") + } + + + String applicationIdentifierPrefix = getApplicationIdentifierPrefix() + String teamIdentifierPrefix = getTeamIdentifierPrefix() + if (teamIdentifierPrefix == null) { + teamIdentifierPrefix = applicationIdentifierPrefix + } + + + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "application-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "com.apple.application-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-kvstore-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-container-identifiers") + + + + + if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { + def modifiedKeychainAccessGroups = [] + keychainAccessGroups.each() { group -> + modifiedKeychainAccessGroups << group.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") + } + plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) + } else { + plistHelper.deleteValueFromPlist(entitlementFile, "keychain-access-groups") + } + + // copy the missing values that are in configuration (xcent or signing.entitlments) to the entitlements for signing + enumerateMissingEntitlements(entitlementFile, configuration) { key, value, action -> + + if (value instanceof String) { + value = this.replaceVariables(value) + } else if (value instanceof List) { + value = this.replaceValuesInList((List) value) + } + + + + switch (action) { + case EntitlementAction.REPLACE: + logger.info("replace in entitlement: {} with {}", key, value) + plistHelper.setValueForPlist(entitlementFile, key, value) + break + case EntitlementAction.ADD: + logger.info("add to entitlement: {} with {}", key, value) + plistHelper.addValueForPlist(entitlementFile, key, value) + break + case EntitlementAction.DELETE: + logger.info("delete to entitlement: {}", key) + plistHelper.deleteValueFromPlist(entitlementFile, key) + break + } + } + + + if (logger.isDebugEnabled()) { + String entitlementsContent = FileUtils.readFileToString(entitlementFile) + logger.debug("entitlements content\n{}", entitlementsContent) + } + } + + private List replaceValuesInList(List list) { + def result = [] + for (Object item : list) { + if (item instanceof String) { + result << replaceVariables((String) item) + } else { + result << item + } + } + return result + } + + private String replaceVariables(String value) { + + if (value.startsWith(APPLICATION_IDENTIFIER_PREFIX)) { + return value.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") + } + return value + } + + private void enumerateMissingEntitlements(File entitlementFile, Configuration configuration, Closure closure) { + if (configuration == null) { + return + } + + Configuration entitlements = new ConfigurationFromPlist(entitlementFile) + Set replaceKeys = configuration.getReplaceEntitlementsKeys() + + for (String key in configuration.getKeys()) { + Object value = configuration.get(key) //plistHelper.getValueFromPlist(xcent, key) + + if (!entitlements.containsKey(key)) { + closure(key, value, EntitlementAction.ADD) + } else if (replaceKeys.contains(key)) { + closure(key, value, EntitlementAction.REPLACE) + } + } + + for (String key in configuration.getDeleteEntitlementsKeys()) { + closure(key, null, EntitlementAction.DELETE) + } + + } + + private void setBundleIdentifierToEntitlementsForValue(File entitlementFile, String bundleIdentifier, String prefix, String value) { + def currentValue = plistHelper.getValueFromPlist(entitlementFile, value) + + if (currentValue == null) { + return + } + + if (currentValue instanceof List) { + def modifiedValues = [] + currentValue.each { item -> + if (item.toString().endsWith('*')) { + modifiedValues << prefix + "." + bundleIdentifier + } + } + plistHelper.setValueForPlist(entitlementFile, value, modifiedValues) + + } else { + if (currentValue.toString().endsWith('*')) { + plistHelper.setValueForPlist(entitlementFile, value, prefix + "." + bundleIdentifier) + } + } + } + + public boolean isAdHoc() { + def provisionedDevices = config.getList("ProvisionedDevices") + return !provisionedDevices.empty + } } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index e90d0215..f4665a14 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -1,13 +1,12 @@ package org.openbakery -import groovy.transform.CompileStatic import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper -@CompileStatic +//@CompileStatic class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader @@ -23,6 +22,8 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { PrepareXcodeArchivingTask() { super() + dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) @@ -36,8 +37,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @Input String getBundleIdentifier() { - File plistFile = new File(project.projectDir, getXcodeExtension().getInfoPlist()) - return plistHelper.getValueFromPlist(plistFile, "CFBundleIdentifier") + return getXcodeExtension().buildConfiguration.bundleIdentifier } Optional getProvisioningFile() { @@ -57,9 +57,14 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @TaskAction void generate() { - getXcConfigFile().text = "//:configuration = GradleXcode" + security.getKeychainList() + getXcConfigFile().text = "" computeProvisioningFile(getProvisioningFile() - .orElseThrow { new IllegalArgumentException() }) + .orElseThrow { + new IllegalArgumentException("Cannot resolve a valid provisioning " + + "profile for bundle identifier : " + + getBundleIdentifier()) + }) } private void computeProvisioningFile(File file) { @@ -72,6 +77,15 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { } private String getCodeSignIdentity() { + //CODE_SIGN_IDENTITY = iPhone Developer: + + File file = new File(URI.create(getXcodeExtension().signing.certificateURI)) + println "file : " + file.exists() + println "file : " + file.absolutePath + + getKeyContent() + .splitEachLine() + return "iPhone Distribution: " + reader.getTeamName() + " (" + reader.getTeamIdentifierPrefix() + ")" @@ -81,4 +95,14 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { getXcConfigFile() .append(System.getProperty("line.separator") + key + " = " + value) } + + private String getKeyContent() { + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + getXcodeExtension().signing.certificatePassword]) + } } From 832d7a14826a274ba5cac3cd984ff9cf24636d2c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 26 Apr 2018 11:48:14 +0100 Subject: [PATCH 046/121] Continue working on the refactoring --- .../PrepareXcodeArchivingTask.groovy | 197 +++++++++--------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index f4665a14..583baa33 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -6,103 +6,108 @@ import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper +import java.util.regex.Pattern + //@CompileStatic class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { - private ProvisioningProfileReader reader - - public static final String NAME = "prepareArchiving" - public static final String FILE_NAME = "archive.xcconfig" - - private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" - private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" - private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" - private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" - private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" - - PrepareXcodeArchivingTask() { - super() - dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) - dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) - - this.description = "Prepare the archive configuration file" - } - - @Input - List getProvisioningUriList() { - return getXcodeExtension().signing.mobileProvisionURI - } - - @Input - String getBundleIdentifier() { - return getXcodeExtension().buildConfiguration.bundleIdentifier - } - - Optional getProvisioningFile() { - List provisioningList = getProvisioningUriList() - .collect { it -> new File(new URI(it)) } - - return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, - provisioningList, - commandRunner, - plistHelper)) - } - - @OutputFile - File getXcConfigFile() { - return new File(PathHelper.resolveArchiveFolder(project), FILE_NAME) - } - - @TaskAction - void generate() { - security.getKeychainList() - getXcConfigFile().text = "" - computeProvisioningFile(getProvisioningFile() - .orElseThrow { - new IllegalArgumentException("Cannot resolve a valid provisioning " + - "profile for bundle identifier : " + - getBundleIdentifier()) - }) - } - - private void computeProvisioningFile(File file) { - reader = new ProvisioningProfileReader(file, commandRunner) - append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) - append(KEY_CODE_SIGN_IDENTITY, getCodeSignIdentity()) - append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) - append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) - append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) - } - - private String getCodeSignIdentity() { - //CODE_SIGN_IDENTITY = iPhone Developer: - - File file = new File(URI.create(getXcodeExtension().signing.certificateURI)) - println "file : " + file.exists() - println "file : " + file.absolutePath - - getKeyContent() - .splitEachLine() - - return "iPhone Distribution: " + - reader.getTeamName() + - " (" + reader.getTeamIdentifierPrefix() + ")" - } - - private void append(String key, String value) { - getXcConfigFile() - .append(System.getProperty("line.separator") + key + " = " + value) - } - - private String getKeyContent() { - return commandRunner.runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + getXcodeExtension().signing.certificatePassword]) - } + private ProvisioningProfileReader reader + + public static final String NAME = "prepareArchiving" + public static final String FILE_NAME = "archive.xcconfig" + + private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" + private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" + private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" + private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" + private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" + private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ + + PrepareXcodeArchivingTask() { + super() + dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) + dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) + + this.description = "Prepare the archive configuration file" + } + + @Input + List getProvisioningUriList() { + return getXcodeExtension().signing.mobileProvisionURI + } + + @Input + String getBundleIdentifier() { + return getXcodeExtension().buildConfiguration.bundleIdentifier + } + + Optional getProvisioningFile() { + List provisioningList = getProvisioningUriList() + .collect { it -> new File(new URI(it)) } + + return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, + provisioningList, + commandRunner, + plistHelper)) + } + + @OutputFile + File getXcConfigFile() { + return new File(PathHelper.resolveArchiveFolder(project), FILE_NAME) + } + + @TaskAction + void generate() { + computeXcConfigFile() + } + + private void computeXcConfigFile() { + getXcConfigFile().text = "" + + computeProvisioningFile(getProvisioningFile() + .orElseThrow { + new IllegalArgumentException("Cannot resolve a valid provisioning " + + "profile for bundle identifier : " + + getBundleIdentifier()) + }) + } + + private void computeProvisioningFile(File file) { + reader = new ProvisioningProfileReader(file, commandRunner) + append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) + append(KEY_CODE_SIGN_IDENTITY, getCodeSignIdentity().orElseThrow { + new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") + }) + append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) + append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) + append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) + } + + private Optional getCodeSignIdentity() { + return Optional.ofNullable(getKeyContent() + .split(System.getProperty("line.separator")) + .find { PATTERN.matcher(it).matches() }) + .map { PATTERN.matcher(it) } + .filter { it.matches() } + .map { it.group("friendlyName") } + } + + private void append(String key, String value) { + getXcConfigFile() + .append(System.getProperty("line.separator") + key + " = " + value) + } + + private String getKeyContent() { + File file = new File(URI.create(getXcodeExtension().signing.certificateURI)) + assert file.exists() + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + getXcodeExtension().signing.certificatePassword]) + } } From cdd8870f073a0bde0c88e2b315b9344ce565f760 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 27 Apr 2018 14:30:10 +0100 Subject: [PATCH 047/121] Add the packer --- .../org/openbakery/util/PathHelper.groovy | 13 +- .../org/openbakery/util/PlistHelper.groovy | 23 ++-- .../org/openbakery/xcode/Xcodebuild.groovy | 13 ++ .../openbakery/AbstractXcodeBuildTask.groovy | 47 ++++++- .../PrepareXcodeArchivingTask.groovy | 47 +------ .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 103 +++++++-------- .../groovy/org/openbakery/XcodePlugin.groovy | 45 +++---- .../packaging/PackageTaskIosAndTvOS.groovy | 117 ++++++++++++++++++ .../signing/ProvisioningInstallTask.groovy | 6 +- .../org/openbakery/signing/Signing.groovy | 2 +- .../openbakery/signing/SigningMethod.groovy | 21 ++++ 11 files changed, 302 insertions(+), 135 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy create mode 100644 plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index 5485f1fb..d53595f8 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -12,6 +12,7 @@ class PathHelper { public static final String IPHONE_OS = "iphoneos" private static final String FOLDER_ARCHIVE = "archive" + private static final String FOLDER_PACKAGE = "package" static File resolvePath(Type type, boolean simulator, @@ -67,14 +68,18 @@ class PathHelper { configuration) } - static File resolveArchiveFolder(Project project) { - return new File(project.getBuildDir(), FOLDER_ARCHIVE) - } - private static File resolveSymRoot(File symRoot, String configuration, String destination) { return new File(symRoot, "${configuration}-${destination}") } + + static File resolveArchiveFolder(Project project) { + return new File(project.getBuildDir(), FOLDER_ARCHIVE) + } + + static File resolvePackageFolder(Project project) { + return new File(project.getBuildDir(), FOLDER_PACKAGE) + } } diff --git a/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy index 48a689e0..256e23d1 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PlistHelper.groovy @@ -17,16 +17,15 @@ class PlistHelper { this.commandRunner = commandRunner } - /** - * Reads the value for the given key from the given plist - * - * @param plist - * @param key - * @param commandRunner The commandRunner to execute commands (This is espacially needed for Unit Tests) - * - * @return returns the value for the given key - */ + * Reads the value for the given key from the given plist + * + * @param plist + * @param key + * @param commandRunner The commandRunner to execute commands (This is espacially needed for Unit Tests) + * + * @return returns the value for the given key + */ def getValueFromPlist(File plist, String key) { try { @@ -75,6 +74,12 @@ class PlistHelper { commandForPlist(plist, "Add :" + key + " string " + value) } + void addDictForPlist(File plist, String key, Map map) { + commandForPlist(plist, "Add :" + key + " dict") + map.keySet() + .each { it -> addValueForPlist(plist, ":$key:$it", map.get(it)) } + } + void addValueForPlist(File plist, String key, Number value) { if (value instanceof Float || value instanceof Double || value instanceof BigDecimal) { commandForPlist(plist, "Add :" + key + " real " + value) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index 114c55fd..b50b3a24 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -42,6 +42,19 @@ class Xcodebuild { } } + public void packageIpa(File archivePath, + File exportPath, + File exportOptionsPlist) { + assert archivePath != null && archivePath.exists() + assert exportPath != null && exportPath.exists() + assert exportOptionsPlist != null && exportOptionsPlist.exists() + + commandRunner.run("xcodebuild", "-exportArchive", + "-archivePath", archivePath.absolutePath, + "-exportPath", exportPath.absolutePath, + "-exportOptionsPlist", exportOptionsPlist.absolutePath) + } + public void archive(String scheme, File outputPath, File xcconfig) { diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index f4426f1c..e60a173c 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -6,11 +6,15 @@ import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.internal.logging.text.StyledTextOutput import org.gradle.internal.logging.text.StyledTextOutputFactory import org.gradle.util.ConfigureUtil +import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.output.XcodeBuildOutputAppender import org.openbakery.xcode.Destination import org.openbakery.xcode.Devices import org.openbakery.xcode.Type import org.openbakery.xcode.XcodebuildParameters + +import java.util.regex.Pattern + /** * User: rene * Date: 15.07.13 @@ -20,9 +24,10 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { XcodebuildParameters parameters = new XcodebuildParameters() - private List destinationsCache + private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ + AbstractXcodeBuildTask() { super() } @@ -98,7 +103,47 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { return project.getExtensions().getByType(XcodeBuildPluginExtension.class) } + String getBundleIdentifier() { + File infoPlist = new File(project.projectDir, getXcodeExtension().infoPlist) + plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") + } + InfoPlistExtension getInfoPlistExtension() { return project.getExtensions().getByType(InfoPlistExtension.class) } + + Optional getProvisioningFile() { + List provisioningList = getProvisioningUriList() + .collect { it -> new File(new URI(it)) } + + return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, + provisioningList, + commandRunner, + plistHelper)) + } + + List getProvisioningUriList() { + return getXcodeExtension().signing.mobileProvisionURI + } + + Optional getCodeSignIdentity() { + return Optional.ofNullable(getKeyContent() + .split(System.getProperty("line.separator")) + .find { PATTERN.matcher(it).matches() }) + .map { PATTERN.matcher(it) } + .filter { it.matches() } + .map { it.group("friendlyName") } + } + + private String getKeyContent() { + File file = new File(URI.create(getXcodeExtension().signing.certificateURI)) + assert file.exists() + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + getXcodeExtension().signing.certificatePassword]) + } } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 583baa33..101e3fa7 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -1,14 +1,13 @@ package org.openbakery +import groovy.transform.CompileStatic import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper -import java.util.regex.Pattern - -//@CompileStatic +@CompileStatic class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader @@ -21,7 +20,6 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" - private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ PrepareXcodeArchivingTask() { super() @@ -34,23 +32,15 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { } @Input + @Override List getProvisioningUriList() { - return getXcodeExtension().signing.mobileProvisionURI + return super.getProvisioningUriList() } @Input + @Override String getBundleIdentifier() { - return getXcodeExtension().buildConfiguration.bundleIdentifier - } - - Optional getProvisioningFile() { - List provisioningList = getProvisioningUriList() - .collect { it -> new File(new URI(it)) } - - return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, - provisioningList, - commandRunner, - plistHelper)) + return super.getBundleIdentifier() } @OutputFile @@ -60,10 +50,6 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @TaskAction void generate() { - computeXcConfigFile() - } - - private void computeXcConfigFile() { getXcConfigFile().text = "" computeProvisioningFile(getProvisioningFile() @@ -85,29 +71,8 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) } - private Optional getCodeSignIdentity() { - return Optional.ofNullable(getKeyContent() - .split(System.getProperty("line.separator")) - .find { PATTERN.matcher(it).matches() }) - .map { PATTERN.matcher(it) } - .filter { it.matches() } - .map { it.group("friendlyName") } - } - private void append(String key, String value) { getXcConfigFile() .append(System.getProperty("line.separator") + key + " = " + value) } - - private String getKeyContent() { - File file = new File(URI.create(getXcodeExtension().signing.certificateURI)) - assert file.exists() - return commandRunner.runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + getXcodeExtension().signing.certificatePassword]) - } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index ecccf890..b3371cd3 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -6,56 +6,59 @@ import org.openbakery.util.PathHelper import org.openbakery.xcode.Xcodebuild @CompileStatic +@CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - public static final String NAME = "archive" - - XcodeBuildArchiveTaskIosAndTvOS() { - super() - - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - dependsOn(PrepareXcodeArchivingTask.NAME) - - this.description = "Prepare the app bundle that it can be archive" - } - - @InputFile - File getXcConfigFile() { - return new File(PathHelper.resolveArchiveFolder(project), - PrepareXcodeArchivingTask.FILE_NAME) - } - - @Input - String getScheme() { - return getXcodeExtension().scheme - } - - @OutputFile - File getOutputTextFile() { - return new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - } - - @OutputDirectory - File getOutputDirectory() { - File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), - getScheme() + ".xcarchive") - archiveDirectory.mkdirs() - return archiveDirectory - } - - @TaskAction - private void archive() { - Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, - commandRunner, - xcode, - parameters, - getDestinations()) - - commandRunner.setOutputFile(getOutputTextFile()) - - xcodeBuild.archive(getScheme(), - getOutputDirectory(), - getXcConfigFile()) - } + public static final String TASK_NAME = "archive" + + XcodeBuildArchiveTaskIosAndTvOS() { + super() + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(PrepareXcodeArchivingTask.NAME) + + this.description = "Prepare the app bundle that it can be archive" + } + + @InputFile + File getXcConfigFile() { + return new File(PathHelper.resolveArchiveFolder(project), + PrepareXcodeArchivingTask.FILE_NAME) + } + + @Input + String getScheme() { + return getXcodeExtension().scheme + } + + @OutputFile + File getOutputTextFile() { + return new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + } + + @OutputDirectory + File getOutputDirectory() { + File archiveDirectory = PathHelper.resolveArchiveFolder(project) + archiveDirectory.mkdirs() + return archiveDirectory + } + + @TaskAction + private void archive() { + Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, + commandRunner, + xcode, + parameters, + getDestinations()) + + commandRunner.setOutputFile(getOutputTextFile()) + + File outputFile = new File(getOutputDirectory(), getScheme() + ".xcarchive") + outputFile.mkdir() + + xcodeBuild.archive(getScheme(), + outputFile, + getXcConfigFile()) + } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 9442da30..c60d9045 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -25,8 +25,8 @@ import org.gradle.api.tasks.testing.Test import org.openbakery.appledoc.AppledocCleanTask import org.openbakery.appledoc.AppledocTask import org.openbakery.appstore.AppstorePluginExtension -import org.openbakery.appstore.AppstoreValidateTask import org.openbakery.appstore.AppstoreUploadTask +import org.openbakery.appstore.AppstoreValidateTask import org.openbakery.carthage.CarthageCleanTask import org.openbakery.carthage.CarthageUpdateTask import org.openbakery.cocoapods.CocoapodsBootstrapTask @@ -45,28 +45,14 @@ import org.openbakery.deploygate.DeployGateUploadTask import org.openbakery.hockeyapp.HockeyAppCleanTask import org.openbakery.hockeyapp.HockeyAppPluginExtension import org.openbakery.hockeyapp.HockeyAppUploadTask -import org.openbakery.hockeykit.HockeyKitArchiveTask -import org.openbakery.hockeykit.HockeyKitCleanTask -import org.openbakery.hockeykit.HockeyKitImageTask -import org.openbakery.hockeykit.HockeyKitManifestTask -import org.openbakery.hockeykit.HockeyKitPluginExtension -import org.openbakery.hockeykit.HockeyKitReleaseNotesTask +import org.openbakery.hockeykit.* import org.openbakery.oclint.OCLintPluginExtension import org.openbakery.oclint.OCLintTask -import org.openbakery.packaging.ReleaseNotesTask -import org.openbakery.signing.KeychainCleanupTask -import org.openbakery.signing.KeychainCreateTask import org.openbakery.packaging.PackageTask -import org.openbakery.signing.KeychainRemoveFromSearchListTask -import org.openbakery.signing.ProvisioningCleanupTask -import org.openbakery.signing.ProvisioningInstallTask -import org.openbakery.simulators.SimulatorKillTask -import org.openbakery.simulators.SimulatorsCleanTask -import org.openbakery.simulators.SimulatorsCreateTask -import org.openbakery.simulators.SimulatorsListTask -import org.openbakery.simulators.SimulatorStartTask -import org.openbakery.simulators.SimulatorRunAppTask -import org.openbakery.simulators.SimulatorInstallAppTask +import org.openbakery.packaging.PackageTaskIosAndTvOS +import org.openbakery.packaging.ReleaseNotesTask +import org.openbakery.signing.* +import org.openbakery.simulators.* import org.openbakery.xcode.Type import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -483,7 +469,7 @@ class XcodePlugin implements Plugin { prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.tasks.create( - XcodeBuildArchiveTaskIosAndTvOS.NAME, + XcodeBuildArchiveTaskIosAndTvOS.TASK_NAME, XcodeBuildArchiveTaskIosAndTvOS.class) archiveTask.setGroup(XCODE_GROUP_NAME) } else { @@ -538,11 +524,22 @@ class XcodePlugin implements Plugin { } private configurePackage(Project project) { - PackageTask packageTask = project.task(PACKAGE_TASK_NAME, type: PackageTask, group: XCODE_GROUP_NAME) + if (project.xcodebuild.type == Type.tvOS + || project.xcodebuild.type == Type.iOS) { + project.task(PackageTaskIosAndTvOS.TASK_NAME, + type: PackageTaskIosAndTvOS, + group: XCODE_GROUP_NAME) + } else { + PackageTask packageTask = project.task(PACKAGE_TASK_NAME, + type: PackageTask, + group: XCODE_GROUP_NAME) - project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) + packageTask.shouldRunAfter(xcodeBuildTask) + } + project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) @@ -553,8 +550,6 @@ class XcodePlugin implements Plugin { keychainCleanupTask.clean() } */ - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) - packageTask.shouldRunAfter(xcodeBuildTask) } private configureAppstore(Project project) { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy new file mode 100644 index 00000000..1c8239e4 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -0,0 +1,117 @@ +package org.openbakery.packaging + +import groovy.transform.CompileStatic +import org.gradle.api.tasks.* +import org.openbakery.AbstractXcodeBuildTask +import org.openbakery.XcodePlugin +import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Xcodebuild + +@CompileStatic +class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { + + private ProvisioningProfileReader reader + + public static final String TASK_NAME = "package" + + private static final String XC_ARCHIVE_EXTENSION = ".xcarchive" + private static final String PLIST_KEY_METHOD = "method" + private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" + private static final String PLIST_KEY_SIGNING_CERTIFICATE = "signingCertificate" + + PackageTaskIosAndTvOS() { + super() + + dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) + + finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) + } + + @Input + String getBundleIdentifier() { + return super.getBundleIdentifier() + } + + @Input + String getMethod() { + return getXcodeExtension().getSigning().method.getValue() + } + + @Input + String getScheme() { + return getXcodeExtension().scheme + } + + @InputDirectory + File getArchiveFile() { + return new File(PathHelper.resolveArchiveFolder(project), + getScheme() + XC_ARCHIVE_EXTENSION) + } + + @OutputDirectory + File getOutputDirectory() { + File file = PathHelper.resolvePackageFolder(project) + file.mkdirs() + return file + } + + @OutputFile + File getExportOptionsPlistFile() { + return new File(project.buildDir, "exportOptions.plist") + } + + @TaskAction + private void packageArchive() { + assert getArchiveFile().exists() && getArchiveFile().isDirectory() + setupProvisioningProfileReader() + generateExportOptionPlist() + packageIt() + } + + private void setupProvisioningProfileReader() { + reader = new ProvisioningProfileReader(getProvisioningFile() + .orElseThrow { + new IllegalArgumentException("Cannot resolve a valid provisioning " + + "profile for bundle identifier : " + + getBundleIdentifier()) + }, commandRunner) + } + + private void generateExportOptionPlist() { + File file = getExportOptionsPlistFile() + + plistHelper.create(file) + plistHelper.addValueForPlist(file, + PLIST_KEY_METHOD, + getMethod()) + + // provisioning profiles + HashMap map = new HashMap<>() + map.put(reader.getApplicationIdentifier(), reader.getName()) + plistHelper.addDictForPlist(file, + PLIST_KEY_PROVISIONING_PROFILE, + map) + + // certificate + plistHelper.addValueForPlist(file, + PLIST_KEY_SIGNING_CERTIFICATE, + getCodeSignIdentity().orElseThrow { + new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") + }) + } + + private void packageIt() { + Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, + commandRunner, + xcode, + parameters, + getDestinations()) + + xcodeBuild.packageIpa(getArchiveFile(), + getOutputDirectory(), + getExportOptionsPlistFile()) + } +} diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 4d1d3bf5..12178bf4 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -19,8 +19,6 @@ import org.apache.commons.io.FilenameUtils import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeTask import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin class ProvisioningInstallTask extends AbstractXcodeTask { @@ -30,7 +28,7 @@ class ProvisioningInstallTask extends AbstractXcodeTask { ProvisioningInstallTask() { super() - dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) +// dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) this.description = "Installs the given provisioning profile" } @@ -85,4 +83,4 @@ class ProvisioningInstallTask extends AbstractXcodeTask { } } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 3bc87880..193940dc 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -13,7 +13,7 @@ class Signing { public final static KEYCHAIN_NAME_BASE = "gradle-" - + SigningMethod method String identity String certificateURI String certificatePassword diff --git a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy new file mode 100644 index 00000000..584fce0c --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy @@ -0,0 +1,21 @@ +package org.openbakery.signing + +enum SigningMethod { + AppStore("app-store"), + AdHoc("ad-hoc"), + Package("package"), + Entreprise("enterprise"), + Developement("development"), + DeveloperId("developer-id"), + MacApplication("mac-application") + + private final String value + + SigningMethod(String value) { + this.value = value + } + + String getValue() { + return value + } +} From 6dbf08024dfe139fad65704507590b61247a67ea Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 27 Apr 2018 14:47:05 +0100 Subject: [PATCH 048/121] More adjustements --- .../packaging/PackageTaskIosAndTvOS.groovy | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 1c8239e4..554e8b81 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -8,6 +8,8 @@ import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper import org.openbakery.xcode.Xcodebuild +import java.util.Optional + @CompileStatic class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @@ -31,18 +33,21 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { } @Input - String getBundleIdentifier() { - return super.getBundleIdentifier() + String getOptionalBundleIdentifier() { + return Optional.ofNullable(super.getBundleIdentifier()) + .orElseThrow { new IllegalArgumentException("Invalid bundle identifier") } } @Input String getMethod() { - return getXcodeExtension().getSigning().method.getValue() + return Optional.ofNullable(getXcodeExtension().getSigning().method.getValue()) + .orElseThrow { new IllegalArgumentException("Invalid signing method") } } @Input String getScheme() { - return getXcodeExtension().scheme + return Optional.ofNullable(getXcodeExtension().scheme) + .orElseThrow { new IllegalArgumentException("Invalid signing method") } } @InputDirectory @@ -76,7 +81,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { .orElseThrow { new IllegalArgumentException("Cannot resolve a valid provisioning " + "profile for bundle identifier : " + - getBundleIdentifier()) + getOptionalBundleIdentifier()) }, commandRunner) } From e21b2c16bc28846f0fce0a9ba0f8eff1cdbb7c35 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 13:54:19 +0100 Subject: [PATCH 049/121] Properly resolve the bundleidentifier depending of the DSL configuration --- .../openbakery/AbstractDistributeTask.groovy | 2 +- .../org/openbakery/InfoPlistModifyTask.groovy | 36 ++++++++----- .../PrepareXcodeArchivingTask.groovy | 26 +++++++--- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 2 +- .../XcodeBuildPluginExtension.groovy | 7 +++ .../InfoPlistModifyTaskSpecification.groovy | 50 ++++++++++++++++++- 6 files changed, 98 insertions(+), 25 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy index e2a36996..23a3e14a 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy @@ -9,7 +9,7 @@ import java.util.regex.Pattern * User: rene * Date: 11/11/14 */ -class AbstractDistributeTask extends AbstractXcodeTask { +class AbstractDistributeTask extends AbstractXcodeBuildTask { private File archiveDirectory; diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 417c45c9..71b71d40 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -17,19 +17,19 @@ package org.openbakery import org.gradle.api.tasks.TaskAction - class InfoPlistModifyTask extends AbstractDistributeTask { File infoPlist Boolean modfied = false + public static final String KeyBundleIdentifier = "CFBundleIdentifier" + public InfoPlistModifyTask() { dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) } @TaskAction def prepare() { - if (!project.infoplist.hasValuesToModify()) { logger.debug("Nothing to modify") return; @@ -45,15 +45,7 @@ class InfoPlistModifyTask extends AbstractDistributeTask { logger.debug("Try to updating {}", infoPlist) - if (project.infoplist.bundleIdentifier != null) { - setValueForPlist("CFBundleIdentifier", project.infoplist.bundleIdentifier) - } - - // add suffix to bundleIdentifier - if (project.infoplist.bundleIdentifierSuffix != null) { - def bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") - setValueForPlist("CFBundleIdentifier", bundleIdentifier + project.infoplist.bundleIdentifierSuffix) - } + modifyBundleIdentifier() // Modify bundle bundleName if (project.infoplist.bundleName != null) { @@ -77,7 +69,7 @@ class InfoPlistModifyTask extends AbstractDistributeTask { modifyShortVersion(infoPlist) - for(String command in project.infoplist.commands) { + for (String command in project.infoplist.commands) { setValueForPlist(command) } @@ -140,9 +132,27 @@ class InfoPlistModifyTask extends AbstractDistributeTask { logger.debug("Modify CFBundleShortVersionString to {}", shortVersionString) setValueForPlist("CFBundleShortVersionString", shortVersionString) - } + private void modifyBundleIdentifier() { + InfoPlistExtension extension = getInfoPlistExtension() + + // Resolve bundle identifier + if (extension.bundleIdentifier != null) { + setValueForPlist(KeyBundleIdentifier, extension.bundleIdentifier) + } else { + XcodeBuildPluginExtension xcodeExtension = getXcodeExtension() + xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme, xcodeExtension.configuration) + .map { it -> it.bundleIdentifier } + .ifPresent { it -> setValueForPlist(KeyBundleIdentifier, it) } + } + + // Add suffix to bundleIdentifier if defined + if (extension.bundleIdentifierSuffix != null) { + String bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, KeyBundleIdentifier) + setValueForPlist(KeyBundleIdentifier, bundleIdentifier + extension.bundleIdentifierSuffix) + } + } void setValueForPlist(String key, String value) { modfied = true diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 101e3fa7..c5674d10 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -37,10 +37,18 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { return super.getProvisioningUriList() } - @Input - @Override String getBundleIdentifier() { - return super.getBundleIdentifier() + String result = super.getBundleIdentifier() + + if (result.contains("\$(PRODUCT_BUNDLE_IDENTIFIER)")) { + File projectFile = new File(getXcodeExtension().projectFile, "project.pbxproj") + XcodeProjectFile pj = new XcodeProjectFile(project, projectFile) + pj.parse() + + result = pj.getBuildConfiguration(getXcodeExtension().target, + getXcodeExtension().configuration).bundleIdentifier + } + return result } @OutputFile @@ -53,11 +61,13 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { getXcConfigFile().text = "" computeProvisioningFile(getProvisioningFile() - .orElseThrow { - new IllegalArgumentException("Cannot resolve a valid provisioning " + - "profile for bundle identifier : " + - getBundleIdentifier()) - }) + .orElseThrow { cannotResolveValidProvisioning() }) + } + + private IllegalArgumentException cannotResolveValidProvisioning() { + return new IllegalArgumentException("Cannot resolve a valid provisioning " + + "profile for bundle identifier : " + + getBundleIdentifier()) } private void computeProvisioningFile(File file) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index b3371cd3..4b574dac 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -14,7 +14,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { XcodeBuildArchiveTaskIosAndTvOS() { super() - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) +// dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index e169cb11..e1216dd5 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -140,6 +140,13 @@ class XcodeBuildPluginExtension { } + Optional getBuildTargetConfiguration(String scheme, + String configuration) { + return Optional.ofNullable(projectSettings.get(scheme, null)) + .map { it -> it.buildSettings } + .map { bs -> (BuildConfiguration) bs.get(configuration) } + } + String getWorkspace() { if (workspace != null) { return workspace diff --git a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy index 0e5d4df0..e3b9fb0d 100644 --- a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy @@ -5,8 +5,9 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.testdouble.PlistHelperStub import spock.lang.Specification +import spock.lang.Unroll -class InfoPlistModifyTaskSpecification extends Specification{ +class InfoPlistModifyTaskSpecification extends Specification { Project project @@ -43,6 +44,51 @@ class InfoPlistModifyTaskSpecification extends Specification{ FileUtils.deleteDirectory(project.projectDir) } + def "add suffix"() { + given: + project.infoplist.bundleIdentifier = 'org.openbakery.test.Example' + project.infoplist.bundleIdentifierSuffix = '.suffix' + + when: + task.prepare() + + then: + plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") == 'org.openbakery.test.Example.suffix' + } + + @Unroll + def "add suffix `#bundleId` suffix : `#suffix`"() { + given: + BuildConfiguration bcRelease = new BuildConfiguration("Target") + bcRelease.bundleIdentifier = bundleId + + BuildTargetConfiguration btc = new BuildTargetConfiguration() + btc.buildSettings[configuration] = bcRelease + + HashMap projectSettings = new HashMap<>() + projectSettings.put(scheme, btc) + + def extension = project.extensions.getByType(XcodeBuildPluginExtension) + extension.projectSettings = projectSettings + extension.scheme = scheme + extension.configuration = configuration + + project.infoplist.bundleIdentifierSuffix = suffix + + when: + task.prepare() + + then: + noExceptionThrown() + plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") == expectedResult + + where: + configuration | scheme | suffix | bundleId | expectedResult + "Release" | "Test" | "suffix" | "he.lllo.world" | "he.lllo.worldsuffix" + "Release" | "Test" | "" | "he.lllo.world" | "he.lllo.world" + "Release" | "Test" | null | "he.lllo.world" | null + "Debug" | "Test" | null | "he.lllo.world" | null + } def "modify BundleIdentifier"() { given: @@ -69,7 +115,7 @@ class InfoPlistModifyTaskSpecification extends Specification{ } def "modify command multiple"() { - project.infoplist.commands = ["Add CFBundleURLTypes:0:CFBundleURLName string", "Add CFBundleURLTypes:0:CFBundleURLSchemes array" ] + project.infoplist.commands = ["Add CFBundleURLTypes:0:CFBundleURLName string", "Add CFBundleURLTypes:0:CFBundleURLSchemes array"] when: task.prepare() From 0260467a63a2908f334985a855862b230d6a9404 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 13:55:47 +0100 Subject: [PATCH 050/121] Fix indentations --- .../codesign/ProvisioningProfileReader.groovy | 652 +++++++++--------- 1 file changed, 326 insertions(+), 326 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy index cc9cc7a5..3f62a32a 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy @@ -31,357 +31,357 @@ import java.text.DateFormat class ProvisioningProfileReader { - enum EntitlementAction { - ADD, REPLACE, DELETE - } + enum EntitlementAction { + ADD, REPLACE, DELETE + } - public static final String APPLICATION_IDENTIFIER_PREFIX = '$(AppIdentifierPrefix)' - protected CommandRunner commandRunner - private PlistHelper plistHelper + public static final String APPLICATION_IDENTIFIER_PREFIX = '$(AppIdentifierPrefix)' + protected CommandRunner commandRunner + private PlistHelper plistHelper - private static Logger logger = LoggerFactory.getLogger(ProvisioningProfileReader.class) + private static Logger logger = LoggerFactory.getLogger(ProvisioningProfileReader.class) - XMLPropertyListConfiguration config + XMLPropertyListConfiguration config - private File provisioningProfile - private File provisioningPlist + private File provisioningProfile + private File provisioningPlist - ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner) { - this(provisioningProfile, commandRunner, new PlistHelper(commandRunner)) - } + ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner) { + this(provisioningProfile, commandRunner, new PlistHelper(commandRunner)) + } - ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner, PlistHelper plistHelper) { - super() + ProvisioningProfileReader(File provisioningProfile, CommandRunner commandRunner, PlistHelper plistHelper) { + super() - logger.debug("load provisioningProfile: {}", provisioningProfile) - String text = load(provisioningProfile) - logger.debug("provisioningProfile content:\n{}\n--- END ---", text) - config = new XMLPropertyListConfiguration() - config.load(new StringReader(text)) + logger.debug("load provisioningProfile: {}", provisioningProfile) + String text = load(provisioningProfile) + logger.debug("provisioningProfile content:\n{}\n--- END ---", text) + config = new XMLPropertyListConfiguration() + config.load(new StringReader(text)) - this.commandRunner = commandRunner + this.commandRunner = commandRunner - this.plistHelper = plistHelper + this.plistHelper = plistHelper - checkExpired() - } + checkExpired() + } - static File getProvisionFileForIdentifier(String bundleIdentifier, List mobileProvisionFiles, CommandRunner commandRunner, PlistHelper plistHelper) { - def provisionFileMap = [:] + static File getProvisionFileForIdentifier(String bundleIdentifier, List mobileProvisionFiles, CommandRunner commandRunner, PlistHelper plistHelper) { + def provisionFileMap = [:] - for (File mobileProvisionFile : mobileProvisionFiles) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileProvisionFile, commandRunner, plistHelper) - provisionFileMap.put(reader.getApplicationIdentifier(), mobileProvisionFile) - } + for (File mobileProvisionFile : mobileProvisionFiles) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileProvisionFile, commandRunner, plistHelper) + provisionFileMap.put(reader.getApplicationIdentifier(), mobileProvisionFile) + } - logger.debug("provisionFileMap: {}", provisionFileMap) + logger.debug("provisionFileMap: {}", provisionFileMap) - for (entry in provisionFileMap) { - if (entry.key.equalsIgnoreCase(bundleIdentifier)) { - return entry.value - } - } + for (entry in provisionFileMap) { + if (entry.key.equalsIgnoreCase(bundleIdentifier)) { + return entry.value + } + } - // match wildcard - for (entry in provisionFileMap) { - if (entry.key.equals("*")) { - return entry.value - } + // match wildcard + for (entry in provisionFileMap) { + if (entry.key.equals("*")) { + return entry.value + } - if (entry.key.endsWith("*")) { - String key = entry.key[0..-2].toLowerCase() - if (bundleIdentifier.toLowerCase().startsWith(key)) { - return entry.value - } - } - } + if (entry.key.endsWith("*")) { + String key = entry.key[0..-2].toLowerCase() + if (bundleIdentifier.toLowerCase().startsWith(key)) { + return entry.value + } + } + } - logger.info("No provisioning profile found for bundle identifier {}", bundleIdentifier) - logger.info("Available bundle identifier are {}" + provisionFileMap.keySet()) + logger.info("No provisioning profile found for bundle identifier {}", bundleIdentifier) + logger.info("Available bundle identifier are {}" + provisionFileMap.keySet()) - return null - } + return null + } - String load(File provisioningProfile) { - this.provisioningProfile = provisioningProfile + String load(File provisioningProfile) { + this.provisioningProfile = provisioningProfile - if (!this.provisioningProfile.exists()) { - logger.warn("The specified provisioning profile does not exist: " + this.provisioningProfile.absolutePath) - return null - } + if (!this.provisioningProfile.exists()) { + logger.warn("The specified provisioning profile does not exist: " + this.provisioningProfile.absolutePath) + return null + } - StringBuffer result = new StringBuffer() - - boolean append = false - for (String line : this.provisioningProfile.text.split("\n")) { - if (line.startsWith("")) { - result.append("") - return result.toString() - } - - if (append) { - result.append(line) - result.append("\n") - } + StringBuffer result = new StringBuffer() + + boolean append = false + for (String line : this.provisioningProfile.text.split("\n")) { + if (line.startsWith("")) { + result.append("") + return result.toString() + } + + if (append) { + result.append(line) + result.append("\n") + } - } - return "" - } - - - boolean checkExpired() { - - Date expireDate = config.getProperty("ExpirationDate") - if (expireDate.before(new Date())) { - DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault()) - throw new IllegalArgumentException("The Provisioning Profile has expired on " + formatter.format(expireDate)) - } - } - - - String getUUID() { - return config.getString("UUID") - } - - String getApplicationIdentifierPrefix() { - return config.getString("ApplicationIdentifierPrefix") - } - - String getTeamIdentifierPrefix() { - return config.getString("TeamIdentifier") - } - - String getTeamName() { - return config.getString("TeamName") - } - - String getName() { - return config.getString("Name") - } - - File getPlistFromProvisioningProfile() { - if (provisioningPlist == null) { - // unpack provisioning profile to plain plist - String basename = FilenameUtils.getBaseName(provisioningProfile.path) - // read temporary plist file - File tmpDir = new File(System.getProperty("java.io.tmpdir")) - provisioningPlist = new File(tmpDir, "provision_" + basename + ".plist") - provisioningPlist.deleteOnExit() - - try { - commandRunner.run(["security", - "cms", - "-D", - "-i", - provisioningProfile.getCanonicalPath(), - "-o", - provisioningPlist.absolutePath - ]) - } catch (CommandRunnerException ex) { - if (!provisioningPlist.exists()) { - throw new IllegalStateException("provisioning plist does not exist: " + provisioningPlist) - } - } - } - return provisioningPlist - } - - String getApplicationIdentifier() { - - String value - - if (this.provisioningProfile.path.endsWith(".mobileprovision")) { - value = config.getProperty("Entitlements.application-identifier") - } else { - value = plistHelper.getValueFromPlist(getPlistFromProvisioningProfile(), "Entitlements:com.apple.application-identifier") - } - - String prefix = getApplicationIdentifierPrefix() + "." - if (value.startsWith(prefix)) { - return value.substring(prefix.length()) - } - return value - } - - /* xcent is the archive entitlements */ - - void extractEntitlements(File entitlementFile, String bundleIdentifier, List keychainAccessGroups, Configuration configuration) { - logger.info("extractEntitlements for " + bundleIdentifier) - File plistFromProvisioningProfile = getPlistFromProvisioningProfile() - String entitlements = commandRunner.runWithResult([ - "/usr/libexec/PlistBuddy", - "-x", - plistFromProvisioningProfile.absolutePath, - "-c", - "Print Entitlements"]) - - if (StringUtils.isEmpty(entitlements)) { - logger.debug("No entitlements found in {}", plistFromProvisioningProfile) - return - } - //String entitlements = plistHelper.commandForPlist(getPlistFromProvisioningProfile(), "Print Entitlements") - FileUtils.writeStringToFile(entitlementFile, entitlements.toString()) - - - - def applicationIdentifier = plistHelper.getValueFromPlist(entitlementFile, "application-identifier") - logger.info("applicationIdentifier from entitlements: {}", applicationIdentifier) - String bundleIdentifierPrefix = "" - if (applicationIdentifier != null) { - String[] tokens = applicationIdentifier.split("\\.") - for (int i = 1; i < tokens.length; i++) { - if (tokens[i] == "*") { - break - } - if (bundleIdentifierPrefix.length() > 0) { - bundleIdentifierPrefix += "." - } - bundleIdentifierPrefix += tokens[i] - } - } - - if (!bundleIdentifier.startsWith(bundleIdentifierPrefix)) { - throw new IllegalStateException("In the provisioning profile a application identifier is specified with " + bundleIdentifierPrefix + " but the app uses a bundle identifier " + bundleIdentifier + " that does not match!") - } - - - String applicationIdentifierPrefix = getApplicationIdentifierPrefix() - String teamIdentifierPrefix = getTeamIdentifierPrefix() - if (teamIdentifierPrefix == null) { - teamIdentifierPrefix = applicationIdentifierPrefix - } - - - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "application-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "com.apple.application-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-kvstore-identifier") - setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-container-identifiers") - - - - - if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { - def modifiedKeychainAccessGroups = [] - keychainAccessGroups.each() { group -> - modifiedKeychainAccessGroups << group.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") - } - plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) - } else { - plistHelper.deleteValueFromPlist(entitlementFile, "keychain-access-groups") - } - - // copy the missing values that are in configuration (xcent or signing.entitlments) to the entitlements for signing - enumerateMissingEntitlements(entitlementFile, configuration) { key, value, action -> - - if (value instanceof String) { - value = this.replaceVariables(value) - } else if (value instanceof List) { - value = this.replaceValuesInList((List) value) - } - - - - switch (action) { - case EntitlementAction.REPLACE: - logger.info("replace in entitlement: {} with {}", key, value) - plistHelper.setValueForPlist(entitlementFile, key, value) - break - case EntitlementAction.ADD: - logger.info("add to entitlement: {} with {}", key, value) - plistHelper.addValueForPlist(entitlementFile, key, value) - break - case EntitlementAction.DELETE: - logger.info("delete to entitlement: {}", key) - plistHelper.deleteValueFromPlist(entitlementFile, key) - break - } - } - - - if (logger.isDebugEnabled()) { - String entitlementsContent = FileUtils.readFileToString(entitlementFile) - logger.debug("entitlements content\n{}", entitlementsContent) - } - } - - private List replaceValuesInList(List list) { - def result = [] - for (Object item : list) { - if (item instanceof String) { - result << replaceVariables((String) item) - } else { - result << item - } - } - return result - } - - private String replaceVariables(String value) { - - if (value.startsWith(APPLICATION_IDENTIFIER_PREFIX)) { - return value.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") - } - return value - } - - private void enumerateMissingEntitlements(File entitlementFile, Configuration configuration, Closure closure) { - if (configuration == null) { - return - } - - Configuration entitlements = new ConfigurationFromPlist(entitlementFile) - Set replaceKeys = configuration.getReplaceEntitlementsKeys() - - for (String key in configuration.getKeys()) { - Object value = configuration.get(key) //plistHelper.getValueFromPlist(xcent, key) - - if (!entitlements.containsKey(key)) { - closure(key, value, EntitlementAction.ADD) - } else if (replaceKeys.contains(key)) { - closure(key, value, EntitlementAction.REPLACE) - } - } - - for (String key in configuration.getDeleteEntitlementsKeys()) { - closure(key, null, EntitlementAction.DELETE) - } - - } - - private void setBundleIdentifierToEntitlementsForValue(File entitlementFile, String bundleIdentifier, String prefix, String value) { - def currentValue = plistHelper.getValueFromPlist(entitlementFile, value) - - if (currentValue == null) { - return - } - - if (currentValue instanceof List) { - def modifiedValues = [] - currentValue.each { item -> - if (item.toString().endsWith('*')) { - modifiedValues << prefix + "." + bundleIdentifier - } - } - plistHelper.setValueForPlist(entitlementFile, value, modifiedValues) - - } else { - if (currentValue.toString().endsWith('*')) { - plistHelper.setValueForPlist(entitlementFile, value, prefix + "." + bundleIdentifier) - } - } - } - - public boolean isAdHoc() { - def provisionedDevices = config.getList("ProvisionedDevices") - return !provisionedDevices.empty - } + } + return "" + } + + + boolean checkExpired() { + + Date expireDate = config.getProperty("ExpirationDate") + if (expireDate.before(new Date())) { + DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault()) + throw new IllegalArgumentException("The Provisioning Profile has expired on " + formatter.format(expireDate)) + } + } + + + String getUUID() { + return config.getString("UUID") + } + + String getApplicationIdentifierPrefix() { + return config.getString("ApplicationIdentifierPrefix") + } + + String getTeamIdentifierPrefix() { + return config.getString("TeamIdentifier") + } + + String getTeamName() { + return config.getString("TeamName") + } + + String getName() { + return config.getString("Name") + } + + File getPlistFromProvisioningProfile() { + if (provisioningPlist == null) { + // unpack provisioning profile to plain plist + String basename = FilenameUtils.getBaseName(provisioningProfile.path) + // read temporary plist file + File tmpDir = new File(System.getProperty("java.io.tmpdir")) + provisioningPlist = new File(tmpDir, "provision_" + basename + ".plist") + provisioningPlist.deleteOnExit() + + try { + commandRunner.run(["security", + "cms", + "-D", + "-i", + provisioningProfile.getCanonicalPath(), + "-o", + provisioningPlist.absolutePath + ]) + } catch (CommandRunnerException ex) { + if (!provisioningPlist.exists()) { + throw new IllegalStateException("provisioning plist does not exist: " + provisioningPlist) + } + } + } + return provisioningPlist + } + + String getApplicationIdentifier() { + + String value + + if (this.provisioningProfile.path.endsWith(".mobileprovision")) { + value = config.getProperty("Entitlements.application-identifier") + } else { + value = plistHelper.getValueFromPlist(getPlistFromProvisioningProfile(), "Entitlements:com.apple.application-identifier") + } + + String prefix = getApplicationIdentifierPrefix() + "." + if (value.startsWith(prefix)) { + return value.substring(prefix.length()) + } + return value + } + + /* xcent is the archive entitlements */ + + void extractEntitlements(File entitlementFile, String bundleIdentifier, List keychainAccessGroups, Configuration configuration) { + logger.info("extractEntitlements for " + bundleIdentifier) + File plistFromProvisioningProfile = getPlistFromProvisioningProfile() + String entitlements = commandRunner.runWithResult([ + "/usr/libexec/PlistBuddy", + "-x", + plistFromProvisioningProfile.absolutePath, + "-c", + "Print Entitlements"]) + + if (StringUtils.isEmpty(entitlements)) { + logger.debug("No entitlements found in {}", plistFromProvisioningProfile) + return + } + //String entitlements = plistHelper.commandForPlist(getPlistFromProvisioningProfile(), "Print Entitlements") + FileUtils.writeStringToFile(entitlementFile, entitlements.toString()) + + + + def applicationIdentifier = plistHelper.getValueFromPlist(entitlementFile, "application-identifier") + logger.info("applicationIdentifier from entitlements: {}", applicationIdentifier) + String bundleIdentifierPrefix = "" + if (applicationIdentifier != null) { + String[] tokens = applicationIdentifier.split("\\.") + for (int i = 1; i < tokens.length; i++) { + if (tokens[i] == "*") { + break + } + if (bundleIdentifierPrefix.length() > 0) { + bundleIdentifierPrefix += "." + } + bundleIdentifierPrefix += tokens[i] + } + } + + if (!bundleIdentifier.startsWith(bundleIdentifierPrefix)) { + throw new IllegalStateException("In the provisioning profile a application identifier is specified with " + bundleIdentifierPrefix + " but the app uses a bundle identifier " + bundleIdentifier + " that does not match!") + } + + + String applicationIdentifierPrefix = getApplicationIdentifierPrefix() + String teamIdentifierPrefix = getTeamIdentifierPrefix() + if (teamIdentifierPrefix == null) { + teamIdentifierPrefix = applicationIdentifierPrefix + } + + + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "application-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, applicationIdentifierPrefix, "com.apple.application-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-kvstore-identifier") + setBundleIdentifierToEntitlementsForValue(entitlementFile, bundleIdentifier, teamIdentifierPrefix, "com.apple.developer.ubiquity-container-identifiers") + + + + + if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { + def modifiedKeychainAccessGroups = [] + keychainAccessGroups.each() { group -> + modifiedKeychainAccessGroups << group.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") + } + plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) + } else { + plistHelper.deleteValueFromPlist(entitlementFile, "keychain-access-groups") + } + + // copy the missing values that are in configuration (xcent or signing.entitlments) to the entitlements for signing + enumerateMissingEntitlements(entitlementFile, configuration) { key, value, action -> + + if (value instanceof String) { + value = this.replaceVariables(value) + } else if (value instanceof List) { + value = this.replaceValuesInList((List) value) + } + + + + switch (action) { + case EntitlementAction.REPLACE: + logger.info("replace in entitlement: {} with {}", key, value) + plistHelper.setValueForPlist(entitlementFile, key, value) + break + case EntitlementAction.ADD: + logger.info("add to entitlement: {} with {}", key, value) + plistHelper.addValueForPlist(entitlementFile, key, value) + break + case EntitlementAction.DELETE: + logger.info("delete to entitlement: {}", key) + plistHelper.deleteValueFromPlist(entitlementFile, key) + break + } + } + + + if (logger.isDebugEnabled()) { + String entitlementsContent = FileUtils.readFileToString(entitlementFile) + logger.debug("entitlements content\n{}", entitlementsContent) + } + } + + private List replaceValuesInList(List list) { + def result = [] + for (Object item : list) { + if (item instanceof String) { + result << replaceVariables((String) item) + } else { + result << item + } + } + return result + } + + private String replaceVariables(String value) { + + if (value.startsWith(APPLICATION_IDENTIFIER_PREFIX)) { + return value.replace(APPLICATION_IDENTIFIER_PREFIX, applicationIdentifierPrefix + ".") + } + return value + } + + private void enumerateMissingEntitlements(File entitlementFile, Configuration configuration, Closure closure) { + if (configuration == null) { + return + } + + Configuration entitlements = new ConfigurationFromPlist(entitlementFile) + Set replaceKeys = configuration.getReplaceEntitlementsKeys() + + for (String key in configuration.getKeys()) { + Object value = configuration.get(key) //plistHelper.getValueFromPlist(xcent, key) + + if (!entitlements.containsKey(key)) { + closure(key, value, EntitlementAction.ADD) + } else if (replaceKeys.contains(key)) { + closure(key, value, EntitlementAction.REPLACE) + } + } + + for (String key in configuration.getDeleteEntitlementsKeys()) { + closure(key, null, EntitlementAction.DELETE) + } + + } + + private void setBundleIdentifierToEntitlementsForValue(File entitlementFile, String bundleIdentifier, String prefix, String value) { + def currentValue = plistHelper.getValueFromPlist(entitlementFile, value) + + if (currentValue == null) { + return + } + + if (currentValue instanceof List) { + def modifiedValues = [] + currentValue.each { item -> + if (item.toString().endsWith('*')) { + modifiedValues << prefix + "." + bundleIdentifier + } + } + plistHelper.setValueForPlist(entitlementFile, value, modifiedValues) + + } else { + if (currentValue.toString().endsWith('*')) { + plistHelper.setValueForPlist(entitlementFile, value, prefix + "." + bundleIdentifier) + } + } + } + + public boolean isAdHoc() { + def provisionedDevices = config.getList("ProvisionedDevices") + return !provisionedDevices.empty + } } From 97302f404c831e1ad3edf89060534d2d19337817 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 15:44:07 +0100 Subject: [PATCH 051/121] Adjustements --- .../openbakery/AbstractXcodeBuildTask.groovy | 1 - .../packaging/PackageTaskIosAndTvOS.groovy | 13 +- .../signing/ProvisioningInstallTask.groovy | 3 +- .../org/openbakery/signing/Signing.groovy | 46 +-- .../openbakery/signing/SigningMethod.groovy | 9 +- .../InfoPlistModifyTaskSpecification.groovy | 10 +- .../signing/SigningSpecification.groovy | 270 ++++++++++-------- 7 files changed, 196 insertions(+), 156 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index e60a173c..308e917f 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -32,7 +32,6 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { super() } - void setTarget(String target) { parameters.target = target } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 554e8b81..9ea72f0d 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -5,6 +5,7 @@ import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper import org.openbakery.xcode.Xcodebuild @@ -19,6 +20,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private static final String XC_ARCHIVE_EXTENSION = ".xcarchive" private static final String PLIST_KEY_METHOD = "method" + private static final String PLIST_KEY_COMPILE_BITCODE = "compileBitcode" private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" private static final String PLIST_KEY_SIGNING_CERTIFICATE = "signingCertificate" @@ -39,8 +41,8 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { } @Input - String getMethod() { - return Optional.ofNullable(getXcodeExtension().getSigning().method.getValue()) + SigningMethod getMethod() { + return Optional.ofNullable(getXcodeExtension().getSigning().method) .orElseThrow { new IllegalArgumentException("Invalid signing method") } } @@ -91,7 +93,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { plistHelper.create(file) plistHelper.addValueForPlist(file, PLIST_KEY_METHOD, - getMethod()) + getMethod().value) // provisioning profiles HashMap map = new HashMap<>() @@ -106,6 +108,11 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { getCodeSignIdentity().orElseThrow { new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") }) + + // BitCode should be compiled only for AppStore builds + plistHelper.addValueForPlist(file, + PLIST_KEY_COMPILE_BITCODE, + getMethod() == SigningMethod.AppStore) } private void packageIt() { diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 12178bf4..f6512c0c 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -18,6 +18,7 @@ package org.openbakery.signing import org.apache.commons.io.FilenameUtils import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeTask +import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader class ProvisioningInstallTask extends AbstractXcodeTask { @@ -28,7 +29,7 @@ class ProvisioningInstallTask extends AbstractXcodeTask { ProvisioningInstallTask() { super() -// dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) + dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) this.description = "Installs the given provisioning profile" } diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 193940dc..2ca46f3a 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -32,7 +32,7 @@ class Signing { Object signingDestinationRoot Object keychainPathInternal final Project project - final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" + final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" CommandRunner commandRunner @@ -40,8 +40,6 @@ class Signing { List mobileProvisionFile = new ArrayList() - - public Signing(Project project) { this.project = project; this.commandRunner = new CommandRunner() @@ -70,6 +68,10 @@ class Signing { this.keychain = project.file(keychain) } + public void setMethod(String method) { + this.method = SigningMethod.fromString(method) + .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") } + } File getSigningDestinationRoot() { return project.file(signingDestinationRoot) @@ -109,16 +111,16 @@ class Signing { } - File getEntitlementsFile() { - if (entitlementsFile != null) { - if (entitlementsFile instanceof File) { - return entitlementsFile - } - return project.file(entitlementsFile) + File getEntitlementsFile() { + if (entitlementsFile != null) { + if (entitlementsFile instanceof File) { + return entitlementsFile + } + return project.file(entitlementsFile) - } - return null - } + } + return null + } boolean hasEntitlementsFile() { return entitlementsFile != null && entitlementsFile.exists() @@ -132,8 +134,6 @@ class Signing { return this.identity } - - public void entitlements(Map entitlements) { this.entitlements = entitlements @@ -143,17 +143,17 @@ class Signing { public String toString() { if (this.keychain != null) { return "Signing{" + - " identity='" + identity + '\'' + - ", mobileProvisionURI='" + mobileProvisionURI + '\'' + - ", keychain='" + keychain + '\'' + - '}'; + " identity='" + identity + '\'' + + ", mobileProvisionURI='" + mobileProvisionURI + '\'' + + ", keychain='" + keychain + '\'' + + '}'; } return "Signing{" + - " identity='" + identity + '\'' + - ", certificateURI='" + certificateURI + '\'' + - ", certificatePassword='" + certificatePassword + '\'' + - ", mobileProvisionURI='" + mobileProvisionURI + '\'' + - '}'; + " identity='" + identity + '\'' + + ", certificateURI='" + certificateURI + '\'' + + ", certificatePassword='" + certificatePassword + '\'' + + ", mobileProvisionURI='" + mobileProvisionURI + '\'' + + '}'; } CodesignParameters getCodesignParameters() { diff --git a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy index 584fce0c..dd8d9dc2 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy @@ -3,11 +3,8 @@ package org.openbakery.signing enum SigningMethod { AppStore("app-store"), AdHoc("ad-hoc"), - Package("package"), Entreprise("enterprise"), - Developement("development"), - DeveloperId("developer-id"), - MacApplication("mac-application") + Dev("development") private final String value @@ -18,4 +15,8 @@ enum SigningMethod { String getValue() { return value } + + public static Optional fromString(value) { + return Optional.ofNullable(values().find { it.getValue() == value }) + } } diff --git a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy index e3b9fb0d..8fa42990 100644 --- a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy @@ -83,11 +83,11 @@ class InfoPlistModifyTaskSpecification extends Specification { plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") == expectedResult where: - configuration | scheme | suffix | bundleId | expectedResult - "Release" | "Test" | "suffix" | "he.lllo.world" | "he.lllo.worldsuffix" - "Release" | "Test" | "" | "he.lllo.world" | "he.lllo.world" - "Release" | "Test" | null | "he.lllo.world" | null - "Debug" | "Test" | null | "he.lllo.world" | null + configuration | scheme | suffix | bundleId | expectedResult + "Release" | "Test" | ".suffix" | "he.llo.world" | "he.llo.world.suffix" + "Release" | "Test" | "" | "he.llo.world" | "he.llo.world" + "Release" | "Test" | null | "he.llo.world" | null + "Debug" | "Test" | null | "he.llo.world" | null } def "modify BundleIdentifier"() { diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index 9ad5759e..e9db4fac 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -6,137 +6,169 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.codesign.CodesignParameters import org.openbakery.configuration.ConfigurationFromMap import spock.lang.Specification +import spock.lang.Unroll class SigningSpecification extends Specification { - Signing signing - Project project - File projectDir + Signing signing + Project project + File projectDir - def setup() { - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") + def setup() { + projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin - signing = new Signing(project) - } + project = ProjectBuilder.builder().withProjectDir(projectDir).build() + project.buildDir = new File(projectDir, 'build').absoluteFile + project.apply plugin: org.openbakery.XcodePlugin + signing = new Signing(project) + } - def cleanup() { - projectDir.delete() - } + def cleanup() { + projectDir.delete() + } - def "has identity"() { - when: - signing.identity = "Me!" - then: - signing.identity == "Me!" - } + def "has identity"() { + when: + signing.identity = "Me!" + then: + signing.identity == "Me!" + } - def "entitlements data set via closure using xcodebuild"() { + @Unroll + def "the signing method can be resolved from a valid string value for method: #method"() { + when: + signing.setMethod(string) - when: - project.xcodebuild.signing { - entitlements 'com.apple.security.application-groups': ['group.com.example.App'] - } + then: + noExceptionThrown() + signing.getMethod() == method - then: - project.xcodebuild.signing.entitlements instanceof Map - project.xcodebuild.signing.entitlements.containsKey("com.apple.security.application-groups") + where: + string | method + "ad-hoc" | SigningMethod.AdHoc + "app-store" | SigningMethod.AppStore + "development" | SigningMethod.Dev + "enterprise" | SigningMethod.Entreprise + } + + def "Should throw an expection when trying to parse an invalid signature method"() { + when: + signing.setMethod(string) - } + then: + thrown(IllegalArgumentException.class) - def "entitlements data set via closure"() { - when: - signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) - - then: - signing.entitlements instanceof Map - signing.entitlements.containsKey("com.apple.security.application-groups") - signing.entitlements["com.apple.security.application-groups"] == ['group.com.example.App'] - } - - - def "entitlements data set via closure converted to Configuration"() { - when: - signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) - - def configuration = new ConfigurationFromMap(signing.entitlements) - - then: - configuration.getStringArray("com.apple.security.application-groups") == ['group.com.example.App'] - - } - - def "codesignParameters is not null"() { - when: - signing.identity = "Me" - - then: - signing.codesignParameters instanceof CodesignParameters - } - - def "codesignParameters has identity"() { - when: - signing.identity = "Me" - then: - signing.codesignParameters.signingIdentity == "Me" - } - - def "codesignParameters has mobileProvisionFiles"() { - when: - - File first = new File(projectDir, "first") - FileUtils.write(first, "first") - File second = new File(projectDir, "second") - FileUtils.write(second, "second") - - signing.addMobileProvisionFile(first) - signing.addMobileProvisionFile(second) - - then: - signing.codesignParameters.mobileProvisionFiles instanceof List - signing.codesignParameters.mobileProvisionFiles == [first, second] - } - - def "codesignParameters has keychain"() { - when: - signing.keychain = new File("my.keychain").absoluteFile - then: - signing.codesignParameters.keychain == new File("my.keychain").absoluteFile - } - - - def "codesignParameters has entitlements"() { - when: - signing.entitlements = ['key': 'value'] - then: - signing.codesignParameters.entitlements == ['key': 'value'] - } - - def "codesignParameters has entitlementsFile"() { - when: - signing.entitlementsFile = new File("entitlements") - then: - signing.codesignParameters.entitlementsFile == new File("entitlements") - } - - - def "codesignParameter entitlementsFile as String"() { - when: - signing.entitlementsFile = "entitlements" - then: - signing.codesignParameters.entitlementsFile instanceof File - signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") - } - - def "codesignParameter entitlementsFile as String full path"() { - when: - signing.entitlementsFile = "file:///entitlements" - then: - signing.codesignParameters.entitlementsFile instanceof File - signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") - } + where: + string | _ + "ad-hc" | _ + "app-stre" | _ + null | _ + } + + def "entitlements data set via closure using xcodebuild"() { + + when: + project.xcodebuild.signing { + entitlements 'com.apple.security.application-groups': ['group.com.example.App'] + } + + then: + project.xcodebuild.signing.entitlements instanceof Map + project.xcodebuild.signing.entitlements.containsKey("com.apple.security.application-groups") + + } + + def "entitlements data set via closure"() { + when: + signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) + + then: + signing.entitlements instanceof Map + signing.entitlements.containsKey("com.apple.security.application-groups") + signing.entitlements["com.apple.security.application-groups"] == ['group.com.example.App'] + } + + + def "entitlements data set via closure converted to Configuration"() { + when: + signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) + + def configuration = new ConfigurationFromMap(signing.entitlements) + + then: + configuration.getStringArray("com.apple.security.application-groups") == ['group.com.example.App'] + + } + + def "codesignParameters is not null"() { + when: + signing.identity = "Me" + + then: + signing.codesignParameters instanceof CodesignParameters + } + + def "codesignParameters has identity"() { + when: + signing.identity = "Me" + then: + signing.codesignParameters.signingIdentity == "Me" + } + + def "codesignParameters has mobileProvisionFiles"() { + when: + + File first = new File(projectDir, "first") + FileUtils.write(first, "first") + File second = new File(projectDir, "second") + FileUtils.write(second, "second") + + signing.addMobileProvisionFile(first) + signing.addMobileProvisionFile(second) + + then: + signing.codesignParameters.mobileProvisionFiles instanceof List + signing.codesignParameters.mobileProvisionFiles == [first, second] + } + + def "codesignParameters has keychain"() { + when: + signing.keychain = new File("my.keychain").absoluteFile + then: + signing.codesignParameters.keychain == new File("my.keychain").absoluteFile + } + + + def "codesignParameters has entitlements"() { + when: + signing.entitlements = ['key': 'value'] + then: + signing.codesignParameters.entitlements == ['key': 'value'] + } + + def "codesignParameters has entitlementsFile"() { + when: + signing.entitlementsFile = new File("entitlements") + then: + signing.codesignParameters.entitlementsFile == new File("entitlements") + } + + + def "codesignParameter entitlementsFile as String"() { + when: + signing.entitlementsFile = "entitlements" + then: + signing.codesignParameters.entitlementsFile instanceof File + signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") + } + + def "codesignParameter entitlementsFile as String full path"() { + when: + signing.entitlementsFile = "file:///entitlements" + then: + signing.codesignParameters.entitlementsFile instanceof File + signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") + } } From 368c83ed0dbc60ac04d61351f024f93d34c1e96d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 16:22:30 +0100 Subject: [PATCH 052/121] Continue to move the path resolution --- .../org/openbakery/util/PathHelper.groovy | 11 +++++++++ .../org/openbakery/xcode/Xcodebuild.groovy | 10 ++++---- .../openbakery/AbstractXcodeBuildTask.groovy | 5 +++- .../PrepareXcodeArchivingTask.groovy | 23 +++---------------- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 9 ++------ .../packaging/PackageTaskIosAndTvOS.groovy | 4 +--- .../org/openbakery/signing/Signing.groovy | 6 ++++- .../openbakery/signing/SigningMethod.groovy | 7 ++++-- .../signing/SigningSpecification.groovy | 2 +- 9 files changed, 38 insertions(+), 39 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index d53595f8..9eb9af6c 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -11,8 +11,10 @@ class PathHelper { public static final String IPHONE_SIMULATOR = "iphonesimulator" public static final String IPHONE_OS = "iphoneos" + private static final String ARCHIVE_FILE_NAME = "archive.xcconfig" private static final String FOLDER_ARCHIVE = "archive" private static final String FOLDER_PACKAGE = "package" + private static final String EXTENSION_XC_ARCHIVE = ".xcarchive" static File resolvePath(Type type, boolean simulator, @@ -79,6 +81,15 @@ class PathHelper { return new File(project.getBuildDir(), FOLDER_ARCHIVE) } + static File resolveArchiveFile(Project project, + String scheme) { + return new File(resolveArchiveFolder(project), scheme + EXTENSION_XC_ARCHIVE) + } + + static File resolveXcConfigFile(Project project) { + return new File(resolveArchiveFolder(project), ARCHIVE_FILE_NAME) + } + static File resolvePackageFolder(Project project) { return new File(project.getBuildDir(), FOLDER_PACKAGE) } diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index b50b3a24..8ed0543d 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -57,16 +57,18 @@ class Xcodebuild { public void archive(String scheme, File outputPath, - File xcconfig) { + File xcConfig) { + outputPath.mkdirs() + assert scheme != null - assert outputPath.exists() && outputPath.isDirectory() - assert xcconfig.exists() && !xcconfig.isDirectory() + assert outputPath.isDirectory() + assert xcConfig.exists() && !xcConfig.isDirectory() commandRunner.run("xcodebuild", ACTION_ARCHIVE, ARGUMENT_SCHEME, scheme, ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, - ARGUMENT_XCCONFIG, xcconfig.absolutePath) + ARGUMENT_XCCONFIG, xcConfig.absolutePath) } def execute(OutputAppender outputAppender, Map environment) { diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 308e917f..4dd9e375 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -125,13 +125,16 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { return getXcodeExtension().signing.mobileProvisionURI } - Optional getCodeSignIdentity() { + String getSignatureFriendlyName() { return Optional.ofNullable(getKeyContent() .split(System.getProperty("line.separator")) .find { PATTERN.matcher(it).matches() }) .map { PATTERN.matcher(it) } .filter { it.matches() } .map { it.group("friendlyName") } + .orElseThrow { + new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") + } } private String getKeyContent() { diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index c5674d10..ee62051c 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -13,8 +13,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader public static final String NAME = "prepareArchiving" - public static final String FILE_NAME = "archive.xcconfig" - + private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" @@ -37,23 +36,9 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { return super.getProvisioningUriList() } - String getBundleIdentifier() { - String result = super.getBundleIdentifier() - - if (result.contains("\$(PRODUCT_BUNDLE_IDENTIFIER)")) { - File projectFile = new File(getXcodeExtension().projectFile, "project.pbxproj") - XcodeProjectFile pj = new XcodeProjectFile(project, projectFile) - pj.parse() - - result = pj.getBuildConfiguration(getXcodeExtension().target, - getXcodeExtension().configuration).bundleIdentifier - } - return result - } - @OutputFile File getXcConfigFile() { - return new File(PathHelper.resolveArchiveFolder(project), FILE_NAME) + return PathHelper.resolveXcConfigFile(project) } @TaskAction @@ -73,9 +58,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private void computeProvisioningFile(File file) { reader = new ProvisioningProfileReader(file, commandRunner) append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) - append(KEY_CODE_SIGN_IDENTITY, getCodeSignIdentity().orElseThrow { - new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") - }) + append(KEY_CODE_SIGN_IDENTITY, getSignatureFriendlyName()) append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index 4b574dac..12bc2d15 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -14,7 +14,6 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { XcodeBuildArchiveTaskIosAndTvOS() { super() -// dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) @@ -23,8 +22,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @InputFile File getXcConfigFile() { - return new File(PathHelper.resolveArchiveFolder(project), - PrepareXcodeArchivingTask.FILE_NAME) + return PathHelper.resolveXcConfigFile(project) } @Input @@ -54,11 +52,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { commandRunner.setOutputFile(getOutputTextFile()) - File outputFile = new File(getOutputDirectory(), getScheme() + ".xcarchive") - outputFile.mkdir() - xcodeBuild.archive(getScheme(), - outputFile, + PathHelper.resolveArchiveFile(project, scheme), getXcConfigFile()) } } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 9ea72f0d..097b42a0 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -105,9 +105,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { // certificate plistHelper.addValueForPlist(file, PLIST_KEY_SIGNING_CERTIFICATE, - getCodeSignIdentity().orElseThrow { - new IllegalArgumentException("Failed to resolve the code signing identity from the certificate ") - }) + getSignatureFriendlyName()) // BitCode should be compiled only for AppStore builds plistHelper.addValueForPlist(file, diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 2ca46f3a..fcbfae27 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -13,7 +13,6 @@ class Signing { public final static KEYCHAIN_NAME_BASE = "gradle-" - SigningMethod method String identity String certificateURI String certificatePassword @@ -39,6 +38,7 @@ class Signing { Object mobileProvisionDestinationRoot List mobileProvisionFile = new ArrayList() + private SigningMethod method public Signing(Project project) { this.project = project; @@ -73,6 +73,10 @@ class Signing { .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") } } + SigningMethod getMethod() { + return method + } + File getSigningDestinationRoot() { return project.file(signingDestinationRoot) } diff --git a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy index dd8d9dc2..307710f1 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/SigningMethod.groovy @@ -1,9 +1,12 @@ package org.openbakery.signing +import groovy.transform.CompileStatic + +@CompileStatic enum SigningMethod { AppStore("app-store"), AdHoc("ad-hoc"), - Entreprise("enterprise"), + Enterprise("enterprise"), Dev("development") private final String value @@ -16,7 +19,7 @@ enum SigningMethod { return value } - public static Optional fromString(value) { + static Optional fromString(value) { return Optional.ofNullable(values().find { it.getValue() == value }) } } diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index e9db4fac..2376f5ad 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -50,7 +50,7 @@ class SigningSpecification extends Specification { "ad-hoc" | SigningMethod.AdHoc "app-store" | SigningMethod.AppStore "development" | SigningMethod.Dev - "enterprise" | SigningMethod.Entreprise + "enterprise" | SigningMethod.Enterprise } def "Should throw an expection when trying to parse an invalid signature method"() { From 7f6f470cb1d62d762a71546ff15dd86efe87b489 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 16:33:13 +0100 Subject: [PATCH 053/121] More path resolution changes --- .../src/main/groovy/org/openbakery/util/PathHelper.groovy | 4 ++++ .../groovy/org/openbakery/PrepareXcodeArchivingTask.groovy | 7 +++++-- .../org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index 9eb9af6c..4b4760aa 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -86,6 +86,10 @@ class PathHelper { return new File(resolveArchiveFolder(project), scheme + EXTENSION_XC_ARCHIVE) } + static File resolveArchivingLogFile(Project project) { + return new File(resolveArchiveFolder(project), "xcodebuild-archive-output.txt") + } + static File resolveXcConfigFile(Project project) { return new File(resolveArchiveFolder(project), ARCHIVE_FILE_NAME) } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index ee62051c..137ecf41 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -11,9 +11,10 @@ import org.openbakery.util.PathHelper class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader + private final File outputFile public static final String NAME = "prepareArchiving" - + private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" @@ -22,12 +23,14 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { PrepareXcodeArchivingTask() { super() + dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) this.description = "Prepare the archive configuration file" + this.outputFile = PathHelper.resolveXcConfigFile(project) } @Input @@ -38,7 +41,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @OutputFile File getXcConfigFile() { - return PathHelper.resolveXcConfigFile(project) + return outputFile } @TaskAction diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index 12bc2d15..d2b457ed 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -8,7 +8,7 @@ import org.openbakery.xcode.Xcodebuild @CompileStatic @CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - + public static final String TASK_NAME = "archive" XcodeBuildArchiveTaskIosAndTvOS() { @@ -32,7 +32,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @OutputFile File getOutputTextFile() { - return new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + return PathHelper.resolveArchivingLogFile(project) } @OutputDirectory From b87d14dd991b03c8bb244ac50bc9d0faf66b292f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 16:48:38 +0100 Subject: [PATCH 054/121] Cleanin up --- .../org/openbakery/AbstractXcodeBuildTask.groovy | 10 +++++++--- .../openbakery/PrepareXcodeArchivingTask.groovy | 14 +++----------- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 2 +- .../packaging/PackageTaskIosAndTvOS.groovy | 15 ++++----------- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 4dd9e375..1e090a46 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -104,21 +104,25 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { String getBundleIdentifier() { File infoPlist = new File(project.projectDir, getXcodeExtension().infoPlist) - plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") + return plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") } InfoPlistExtension getInfoPlistExtension() { return project.getExtensions().getByType(InfoPlistExtension.class) } - Optional getProvisioningFile() { + File getProvisioningFile() { List provisioningList = getProvisioningUriList() .collect { it -> new File(new URI(it)) } return Optional.ofNullable(ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, provisioningList, commandRunner, - plistHelper)) + plistHelper)).orElseThrow { + new IllegalArgumentException("Cannot resolve a valid provisioning " + + "profile for bundle identifier : " + + bundleIdentifier) + } } List getProvisioningUriList() { diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 137ecf41..a350592a 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -47,19 +47,11 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @TaskAction void generate() { getXcConfigFile().text = "" - - computeProvisioningFile(getProvisioningFile() - .orElseThrow { cannotResolveValidProvisioning() }) - } - - private IllegalArgumentException cannotResolveValidProvisioning() { - return new IllegalArgumentException("Cannot resolve a valid provisioning " + - "profile for bundle identifier : " + - getBundleIdentifier()) + computeProvisioningFile() } - private void computeProvisioningFile(File file) { - reader = new ProvisioningProfileReader(file, commandRunner) + private void computeProvisioningFile() { + reader = new ProvisioningProfileReader(getProvisioningFile(), commandRunner) append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) append(KEY_CODE_SIGN_IDENTITY, getSignatureFriendlyName()) append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index d2b457ed..be291de9 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -8,7 +8,7 @@ import org.openbakery.xcode.Xcodebuild @CompileStatic @CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - + public static final String TASK_NAME = "archive" XcodeBuildArchiveTaskIosAndTvOS() { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 097b42a0..0d838fc5 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -18,7 +18,6 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { public static final String TASK_NAME = "package" - private static final String XC_ARCHIVE_EXTENSION = ".xcarchive" private static final String PLIST_KEY_METHOD = "method" private static final String PLIST_KEY_COMPILE_BITCODE = "compileBitcode" private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" @@ -35,9 +34,8 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { } @Input - String getOptionalBundleIdentifier() { - return Optional.ofNullable(super.getBundleIdentifier()) - .orElseThrow { new IllegalArgumentException("Invalid bundle identifier") } + String getBundleIdentifier() { + return super.getBundleIdentifier() } @Input @@ -54,8 +52,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @InputDirectory File getArchiveFile() { - return new File(PathHelper.resolveArchiveFolder(project), - getScheme() + XC_ARCHIVE_EXTENSION) + return PathHelper.resolveArchiveFile(project, scheme) } @OutputDirectory @@ -80,11 +77,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private void setupProvisioningProfileReader() { reader = new ProvisioningProfileReader(getProvisioningFile() - .orElseThrow { - new IllegalArgumentException("Cannot resolve a valid provisioning " + - "profile for bundle identifier : " + - getOptionalBundleIdentifier()) - }, commandRunner) + , commandRunner) } private void generateExportOptionPlist() { From 6701374bb4b0576eae7d2d8130d7b78959ba6e96 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 30 Apr 2018 16:59:53 +0100 Subject: [PATCH 055/121] Adjust the implementation --- .../org/openbakery/xcode/Xcodebuild.groovy | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index 8ed0543d..23ebd066 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -15,9 +15,13 @@ class Xcodebuild { XcodebuildParameters parameters List destinations + 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_SCHEME = "-scheme" public static final String ARGUMENT_ARCHIVE_PATH = "-archivePath" + public static final String ARGUMENT_EXPORT_PATH = "-exportPath" + public static final String ARGUMENT_EXPORT_OPTIONS_PLIST = "-exportOptionsPlist" public static final String ARGUMENT_XCCONFIG = "-xcconfig" public Xcodebuild(File projectDirectory, CommandRunner commandRunner, Xcode xcode, XcodebuildParameters parameters, List destinations) { @@ -45,14 +49,16 @@ class Xcodebuild { public void packageIpa(File archivePath, File exportPath, File exportOptionsPlist) { + assert archivePath != null && archivePath.exists() assert exportPath != null && exportPath.exists() assert exportOptionsPlist != null && exportOptionsPlist.exists() - commandRunner.run("xcodebuild", "-exportArchive", - "-archivePath", archivePath.absolutePath, - "-exportPath", exportPath.absolutePath, - "-exportOptionsPlist", exportOptionsPlist.absolutePath) + commandRunner.run(EXECUTABLE, + ACTION_EXPORT_ARCHIVE, + ARGUMENT_ARCHIVE_PATH, archivePath.absolutePath, + ARGUMENT_EXPORT_PATH, exportPath.absolutePath, + ARGUMENT_EXPORT_OPTIONS_PLIST, exportOptionsPlist.absolutePath) } public void archive(String scheme, @@ -64,7 +70,7 @@ class Xcodebuild { assert outputPath.isDirectory() assert xcConfig.exists() && !xcConfig.isDirectory() - commandRunner.run("xcodebuild", + commandRunner.run(EXECUTABLE, ACTION_ARCHIVE, ARGUMENT_SCHEME, scheme, ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, From 55d8f1ca531a85b09fbff3c1d572642338c14c5c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:30:51 +0100 Subject: [PATCH 056/121] The entitlements were not injected properly --- .../org/openbakery/PrepareXcodeArchivingTask.groovy | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index a350592a..fa5aa009 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -7,6 +7,8 @@ import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper +import java.util.function.Consumer + @CompileStatic class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { @@ -17,6 +19,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" + private static final String KEY_CODE_SIGN_ENTITLEMENTS = "CODE_SIGN_ENTITLEMENTS" private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" @@ -57,6 +60,14 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) + + Optional.ofNullable(getXcodeExtension().signing.entitlementsFile) + .ifPresent(new Consumer() { + @Override + void accept(File file) { + append(KEY_CODE_SIGN_ENTITLEMENTS, file.absolutePath) + } + }) } private void append(String key, String value) { From 8dc0c3fd90bd5b810fafaee35438a6d16d1b226b Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:43:45 +0100 Subject: [PATCH 057/121] Use the path reoslver --- libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy | 2 +- .../main/groovy/org/openbakery/AbstractDistributeTask.groovy | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index 4b4760aa..da606db0 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -10,9 +10,9 @@ class PathHelper { public static final String APPLE_TV_SIMULATOR = "appletvsimulator" public static final String IPHONE_SIMULATOR = "iphonesimulator" public static final String IPHONE_OS = "iphoneos" + public static final String FOLDER_ARCHIVE = "archive" private static final String ARCHIVE_FILE_NAME = "archive.xcconfig" - private static final String FOLDER_ARCHIVE = "archive" private static final String FOLDER_PACKAGE = "package" private static final String EXTENSION_XC_ARCHIVE = ".xcarchive" diff --git a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy index 23a3e14a..14c408f3 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy @@ -2,6 +2,7 @@ package org.openbakery import org.apache.commons.io.FileUtils import org.openbakery.packaging.PackageTask +import org.openbakery.util.PathHelper import java.util.regex.Pattern @@ -132,7 +133,7 @@ class AbstractDistributeTask extends AbstractXcodeBuildTask { if (archiveDirectory != null) { return archiveDirectory; } - File archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER) + File archiveDirectory = PathHelper.resolveArchiveFolder(project) if (!archiveDirectory.exists()) { throw new IllegalStateException("Archive does not exist: " + archiveDirectory) } From 2c0b95adab6a103a8bf64b89905d13fad576f754 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:45:55 +0100 Subject: [PATCH 058/121] Use the pathhelper resolver in the test too --- .../deploygate/DeployGateUploadTaskSpecification.groovy | 5 ++--- .../openbakery/hockeyapp/HockeyAppTaskSpecification.groovy | 5 ++--- .../hockeykit/HockeyKitArchiveTaskSpecification.groovy | 5 ++--- .../hockeykit/HockeyKitManifestTaskSpecification.groovy | 4 ++-- .../openbakery/packaging/PackageTaskSpecification.groovy | 3 ++- .../packaging/PackageTask_OSXSpecification.groovy | 6 +++--- .../packaging/PackageTask_WatchAppSpecification.groovy | 6 +++--- .../packaging/PackageTask_WatchKitSpecification.groovy | 6 +++--- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/deploygate/DeployGateUploadTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/deploygate/DeployGateUploadTaskSpecification.groovy index 453ea54a..de8e1fce 100644 --- a/plugin/src/test/groovy/org/openbakery/deploygate/DeployGateUploadTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/deploygate/DeployGateUploadTaskSpecification.groovy @@ -3,9 +3,8 @@ package org.openbakery.deploygate import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder -import org.openbakery.XcodeBuildArchiveTask +import org.openbakery.util.PathHelper import spock.lang.Specification - /** * User: rene * Date: 11/11/14 @@ -31,7 +30,7 @@ class DeployGateUploadTaskSpecification extends Specification { File ipaBundle = new File(project.getBuildDir(), "package/Test.ipa") FileUtils.writeStringToFile(ipaBundle, "dummy") - File archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Test.xcarchive") + File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Test.xcarchive") archiveDirectory.mkdirs() infoPlist = new File(archiveDirectory, "Products/Applications/Test.app/Info.plist"); diff --git a/plugin/src/test/groovy/org/openbakery/hockeyapp/HockeyAppTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/hockeyapp/HockeyAppTaskSpecification.groovy index 09ffd484..dc1f9ff8 100644 --- a/plugin/src/test/groovy/org/openbakery/hockeyapp/HockeyAppTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/hockeyapp/HockeyAppTaskSpecification.groovy @@ -4,9 +4,8 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.XcodeBuildArchiveTask +import org.openbakery.util.PathHelper import spock.lang.Specification - /** * User: rene * Date: 11/11/14 @@ -36,7 +35,7 @@ class HockeyAppTaskSpecification extends Specification { File ipaBundle = new File(project.getBuildDir(), "package/Test.ipa") FileUtils.writeStringToFile(ipaBundle, "dummy") - File archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Test.xcarchive") + File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Test.xcarchive") archiveDirectory.mkdirs() infoPlist = new File(archiveDirectory, "Products/Applications/Test.app/Info.plist"); diff --git a/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitArchiveTaskSpecification.groovy index a73dc8f1..67be1f1c 100644 --- a/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitArchiveTaskSpecification.groovy @@ -4,10 +4,9 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner +import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper -import org.openbakery.XcodeBuildArchiveTask import spock.lang.Specification - /** * User: rene * Date: 11/11/14 @@ -38,7 +37,7 @@ class HockeyKitArchiveTaskSpecification extends Specification { File ipaBundle = new File(project.getBuildDir(), "package/Test.ipa") FileUtils.writeStringToFile(ipaBundle, "dummy") - File archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Test.xcarchive") + File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Test.xcarchive") archiveDirectory.mkdirs() infoPlist = new File(archiveDirectory, "Products/Applications/Test.app/Info.plist"); diff --git a/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitManifestTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitManifestTaskSpecification.groovy index 52f940c1..2dcf7b85 100644 --- a/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitManifestTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/hockeykit/HockeyKitManifestTaskSpecification.groovy @@ -5,7 +5,7 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.testdouble.PlistHelperStub -import org.openbakery.XcodeBuildArchiveTask +import org.openbakery.util.PathHelper import spock.lang.Specification class HockeyKitManifestTaskSpecification extends Specification { @@ -35,7 +35,7 @@ class HockeyKitManifestTaskSpecification extends Specification { hockeyKitManifestTask.commandRunner = commandRunner - File archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Test.xcarchive") + File archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Test.xcarchive") archiveDirectory.mkdirs() infoPlist = new File(archiveDirectory, "Products/Applications/Test.app/Info.plist"); diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 0e036d2a..52127684 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -8,6 +8,7 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.appledoc.AppledocCleanTask import org.openbakery.test.ApplicationDummy +import org.openbakery.util.PathHelper import org.openbakery.xcode.Extension import org.openbakery.xcode.Type import org.openbakery.XcodeBuildArchiveTask @@ -88,7 +89,7 @@ class PackageTaskSpecification extends Specification { void mockExampleApp(boolean withPlugin, boolean withSwift, boolean withFramework = false, boolean adHoc = true, boolean bitcode = false) { outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) - archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Example.xcarchive") + archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") File payloadDirectory = new File(outputPath, "Payload") payloadAppDirectory = new File(payloadDirectory, "Example.app"); diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy index ff27bf8d..130dcb60 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy @@ -5,11 +5,11 @@ import org.apache.commons.io.FilenameUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.xcode.Type -import org.openbakery.XcodeBuildArchiveTask import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type import spock.lang.Specification import java.util.zip.ZipEntry @@ -65,7 +65,7 @@ class PackageTask_OSXSpecification extends Specification { provisionLibraryPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); - archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Example.xcarchive") + archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy index dda0a4f6..c140b01a 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy @@ -4,11 +4,11 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.xcode.Type -import org.openbakery.XcodeBuildArchiveTask import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type import spock.lang.Specification class PackageTask_WatchAppSpecification extends Specification { @@ -57,7 +57,7 @@ class PackageTask_WatchAppSpecification extends Specification { provisionLibraryPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); - archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Example.xcarchive") + archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy index 3e13af3e..6e421aa9 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy @@ -4,11 +4,11 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.xcode.Type -import org.openbakery.XcodeBuildArchiveTask import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type import spock.lang.Specification class PackageTask_WatchKitSpecification extends Specification { @@ -53,7 +53,7 @@ class PackageTask_WatchKitSpecification extends Specification { provisionLibraryPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); - archiveDirectory = new File(project.getBuildDir(), XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/Example.xcarchive") + archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) From 8193aa965144fb497a4dadc4a28a26fb6a9fd9f7 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:46:23 +0100 Subject: [PATCH 059/121] Use the pathhelper resolver in the test too --- .../packaging/PackageTaskSpecification.groovy | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 52127684..9f43b242 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -6,16 +6,14 @@ import org.apache.commons.lang.RandomStringUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.appledoc.AppledocCleanTask -import org.openbakery.test.ApplicationDummy -import org.openbakery.util.PathHelper -import org.openbakery.xcode.Extension -import org.openbakery.xcode.Type -import org.openbakery.XcodeBuildArchiveTask import org.openbakery.XcodePlugin import org.openbakery.output.StyledTextOutputStub +import org.openbakery.test.ApplicationDummy import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Extension +import org.openbakery.xcode.Type import spock.lang.Specification import java.util.zip.ZipEntry From cb15f36763b76487e53985c7b049758cf92ee70f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:50:32 +0100 Subject: [PATCH 060/121] Use the path reoslver --- .../main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index cc48cdaf..49690780 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -19,6 +19,7 @@ import groovy.io.FileType import org.apache.commons.io.FileUtils import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Extension import org.openbakery.xcode.Xcodebuild @@ -40,7 +41,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { def getOutputDirectory() { - def archiveDirectory = new File(project.getBuildDir(), ARCHIVE_FOLDER) + def archiveDirectory = PathHelper.resolveArchiveFolder(project) archiveDirectory.mkdirs() return archiveDirectory } @@ -513,7 +514,8 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { File getArchiveDirectory() { - def archiveDirectoryName = XcodeBuildArchiveTask.ARCHIVE_FOLDER + "/" + project.xcodebuild.bundleName + def archiveDirectoryName = new File(PathHelper.resolveArchiveFolder(project), + getXcodeExtension().bundleName) if (project.xcodebuild.bundleNameSuffix != null) { archiveDirectoryName += project.xcodebuild.bundleNameSuffix From 18ee99d2d512accf8ed00dbafcf8a9c91efa4224 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 13:52:55 +0100 Subject: [PATCH 061/121] No more necessary --- .../src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 49690780..6bbb1e5d 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -28,8 +28,6 @@ import static groovy.io.FileType.FILES class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { - public static final String ARCHIVE_FOLDER = "archive" - XcodeBuildArchiveTask() { super() From 4e42662b77c9659e22632497ab231c9ed2c09276 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 14:37:58 +0100 Subject: [PATCH 062/121] Inherit the legacy archiver, and make it run ifonly iOS or TvOS project --- .../openbakery/XcodeBuildArchiveTask.groovy | 524 +---------------- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 15 +- .../XcodeBuildLegacyArchiveTask.groovy | 541 ++++++++++++++++++ .../XcodeBuildPluginExtension.groovy | 3 + .../groovy/org/openbakery/XcodePlugin.groovy | 30 +- ...odeBuildArchiveTaskOSXSpecification.groovy | 2 +- .../XcodeBuildArchiveTaskSpecification.groovy | 2 +- .../XcodePluginSpecification.groovy | 2 +- 8 files changed, 579 insertions(+), 540 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 6bbb1e5d..3eee7d58 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -1,529 +1,13 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.openbakery -import groovy.io.FileType -import org.apache.commons.io.FileUtils -import org.gradle.api.tasks.TaskAction -import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.util.PathHelper -import org.openbakery.xcode.Type -import org.openbakery.xcode.Extension -import org.openbakery.xcode.Xcodebuild - -import static groovy.io.FileType.FILES - class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { + public static final String NAME = "archive" + XcodeBuildArchiveTask() { super() - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME) - // when creating an xcarchive for iOS then the provisioning profile is need for the team id so that the entitlements is setup properly - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) - this.description = "Prepare the app bundle that it can be archive" - } - - - def getOutputDirectory() { - def archiveDirectory = PathHelper.resolveArchiveFolder(project) - archiveDirectory.mkdirs() - return archiveDirectory + dependsOn(XcodeBuildArchiveTaskIosAndTvOS.NAME, + XcodeBuildLegacyArchiveTask.NAME) } - - - def getiOSIcons() { - ArrayList icons = new ArrayList<>(); - - File applicationBundle = parameters.applicationBundle - def fileList = applicationBundle.list( - [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png - ).toList() - - def applicationPath = "Applications/" + parameters.applicationBundleName - - for (String item in fileList) { - icons.add(applicationPath + "/" + item) - } - - - return icons - } - - def getMacOSXIcons() { - File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") - ArrayList icons = new ArrayList<>(); - - def icnsFileName = plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile") - - if (icnsFileName == null || icnsFileName == "") { - return icons - } - - def iconPath = "Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + icnsFileName + ".icns" - icons.add(iconPath) - - return icons - } - - - def getValueFromBundleInfoPlist(File bundle, String key) { - File appInfoPlist - if (parameters.type == Type.macOS) { - appInfoPlist = new File(bundle, "Contents/Info.plist") - } else { - appInfoPlist = new File(bundle, "Info.plist") - } - return plistHelper.getValueFromPlist(appInfoPlist, key) - } - - - def createInfoPlist(def applicationsDirectory) { - - StringBuilder content = new StringBuilder(); - - - def name = parameters.bundleName - def schemeName = name - def applicationPath = "Applications/" + parameters.applicationBundleName - def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") - int time = System.currentTimeMillis() / 1000; - - def creationDate = formatDate(new Date()); - - def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") - def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") - - List icons - if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { - icons = getiOSIcons() - } else { - icons = getMacOSXIcons() - } - - content.append("\n") - content.append("\n") - content.append("\n") - content.append("\n") - content.append(" ApplicationProperties\n") - content.append(" \n") - content.append(" ApplicationPath\n") - content.append(" " + applicationPath + "\n") - content.append(" CFBundleIdentifier\n") - content.append(" " + bundleIdentifier + "\n") - - if (shortBundleVersion != null) { - content.append(" CFBundleShortVersionString\n") - content.append(" " + shortBundleVersion + "\n") - } - - if (bundleVersion != null) { - content.append(" CFBundleVersion\n") - content.append(" " + bundleVersion + "\n") - } - - if (getSigningIdentity()) { - content.append(" SigningIdentity\n") - content.append(" " + getSigningIdentity() + "\n") - - } - - if (icons.size() > 0) { - content.append(" IconPaths\n") - content.append(" \n") - for (String icon : icons) { - content.append(" " + icon + "\n") - } - content.append(" \n") - } - - content.append(" \n") - content.append(" ArchiveVersion\n") - content.append(" 2\n") - content.append(" CreationDate\n") - content.append(" " + creationDate + "\n") - content.append(" Name\n") - content.append(" " + name + "\n") - content.append(" SchemeName\n") - content.append(" " + schemeName + "\n") - content.append("\n") - content.append("") - - File infoPlist = new File(applicationsDirectory, "Info.plist") - FileUtils.writeStringToFile(infoPlist, content.toString()) - } - - - def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { - - File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") - if (frameworksPath.exists()) { - - - def libNames = [] - frameworksPath.eachFile() { - libNames.add(it.getName()) - } - - logger.debug("swiftlibs to add: {}", libNames); - - File swiftLibs = new File(xcodebuild.getToolchainDirectory(), - "usr/lib/swift/" + getSwiftLibFolderName()) - - logger.debug("swiftlibs to add: {}", swiftLibs); - - swiftLibs.eachFile() { - logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) - if (libNames.contains(it.name)) { - copy(it, getSwiftSupportDirectory()) - } - } - } - - } - - public String getSwiftLibFolderName() { - String result - switch (parameters.type) { - case Type.tvOS: - result = "appletvos" - break - - case Type.iOS: - result = "iphoneos" - break - - default: - break - } - - return result - } - - def getSwiftSupportDirectory() { - def swiftSupportPath = "SwiftSupport" - - if (xcode.version.major > 6) { - swiftSupportPath += "/" + getSwiftLibFolderName() - } - - File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) - if (!swiftSupportDirectory.exists()) { - swiftSupportDirectory.mkdirs() - } - return swiftSupportDirectory - } - - def deleteDirectoryIfEmpty(File base, String child) { - File directory = new File(base, child) - if (directory.exists() && directory.list().length == 0) { - directory.deleteDir(); - } - } - - def deleteEmptyFrameworks(File applicationsDirectory) { - // if frameworks directory is emtpy - File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) - deleteDirectoryIfEmpty(appPath, "Frameworks") - - - } - - def deleteFrameworksInExtension(File applicationsDirectory) { - - - File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") - if (!plugins.exists()) { - return - } - - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith(".appex")) { - File frameworkDirectory = new File(file, "Frameworks"); - if (frameworkDirectory.exists()) { - FileUtils.deleteDirectory(frameworkDirectory) - } - } - } - - } - - - def copyDsyms(File archiveDirectory, File dSymDirectory) { - - archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> - if (directory.toString().toLowerCase().endsWith(".dsym")) { - copy(directory, dSymDirectory) - } - } - - } - - def createEntitlements(File bundle) { - - if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { - logger.warn("Entitlements handling is only implemented for iOS and tvOS!") - return - } - - String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") - if (bundleIdentifier == null) { - logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) - return - } - BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) - if (buildConfiguration == null) { - logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) - return - } - - File destinationDirectory = getDestinationDirectoryForBundle(bundle) - if (buildConfiguration.entitlements) { - File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") - FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) - modifyEntitlementsFile(entitlementFile, bundleIdentifier) - } - } - - def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { - if (!entitlementFile.exists()) { - logger.warn("Entitlements File does not exist {}", entitlementFile) - return - } - - String applicationIdentifier = "UNKNOWN00ID"; // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback - File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) - if (provisioningProfile != null && provisioningProfile.exists()) { - ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) - applicationIdentifier = reader.getApplicationIdentifierPrefix() - } - - plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) - - List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") - - if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { - def modifiedKeychainAccessGroups = [] - keychainAccessGroups.each() { group -> - modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") - } - plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) - } - } - - def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { - String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") - if (extensionIdentifier == null) { - logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) - return - } - - Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) - if (extension == null) { - logger.warn("Extension type not supported", extensionIdentifier) - return - } - - switch (extension) { - case Extension.sticker: - File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") - if (supportDirectory.mkdirs()) { - File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") - copy(stub, supportDirectory) - } - break - default: - break - } - } - - @TaskAction - def archive() { - parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) - if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { - logger.debug("Create zip archive") - - // create zip archive - String zipFileName = parameters.bundleName - if (project.xcodebuild.bundleNameSuffix != null) { - zipFileName += project.xcodebuild.bundleNameSuffix - } - zipFileName += ".zip" - - def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) - def baseDirectory = parameters.applicationBundle.parentFile - - createZip(zipFile, baseDirectory, parameters.applicationBundle) - return - } - - logger.debug("Create xcarchive") - Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) - - if (project.xcodebuild.useXcodebuildArchive) { - - File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") - commandRunner.setOutputFile(outputFile) - - xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) - - return - } - - // create xcarchive - // copy application bundle - copy(parameters.applicationBundle, getApplicationsDirectory()) - - File onDemandResources = new File(parameters.outputPath, "OnDemandResources") - if (onDemandResources.exists()) { - copy(onDemandResources, getProductsDirectory()) - } - - // copy onDemandResources - - def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") - dSymDirectory.mkdirs() - copyDsyms(parameters.outputPath, dSymDirectory) - - List appBundles = getAppBundles(parameters.outputPath) - for (File bundle : appBundles) { - createEntitlements(bundle) - createExtensionSupportDirectory(bundle, xcodebuild) - } - - File applicationsDirectory = getApplicationsDirectory() - - File archiveDirectory = getArchiveDirectory() - createInfoPlist(archiveDirectory) - createFrameworks(archiveDirectory, xcodebuild) - deleteEmptyFrameworks(archiveDirectory) - deleteXCTestIfExists(applicationsDirectory) - deleteFrameworksInExtension(applicationsDirectory) - copyBCSymbolMaps(archiveDirectory) - - if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { - File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) - convertInfoPlistToBinary(applicationFolder) - - removeUnneededDylibsFromBundle(applicationFolder) - } - - logger.debug("create archive done") - } - - def copyBCSymbolMaps(File archiveDirectory) { - if (!parameters.bitcode) { - logger.debug("bitcode is not activated, so to not create BCSymbolMaps") - return - } - File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") - bcSymbolMapsDirectory.mkdirs() - - parameters.outputPath.eachFileRecurse { file -> - if (file.toString().endsWith(".bcsymbolmap")) { - FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) - } - } - - } - - // TODO: Define a `exportOptionsPlist` to avoid that kind of issue - def removeUnneededDylibsFromBundle(File bundle) { - File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") - if (libswiftRemoteMirror.exists()) { - libswiftRemoteMirror.delete() - } - } - - def deleteXCTestIfExists(File applicationsDirectory) { - File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") - if (!plugins.exists()) { - return - } - plugins.eachFile(FileType.DIRECTORIES) { file -> - if (file.toString().endsWith("xctest")) { - FileUtils.deleteDirectory(file) - return true - } - } - } - - File getProductsDirectory() { - File productsDirectory = new File(getArchiveDirectory(), "Products") - productsDirectory.mkdirs() - return productsDirectory - } - - File getApplicationsDirectory() { - File applicationsDirectory = new File(getProductsDirectory(), "Applications") - applicationsDirectory.mkdirs() - return applicationsDirectory - } - - File getDestinationDirectoryForBundle(File bundle) { - String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); - return new File(getApplicationsDirectory(), relative) - } - - def convertInfoPlistToBinary(File archiveDirectory) { - - archiveDirectory.eachFileRecurse(FILES) { - if (it.name.endsWith('.plist')) { - logger.debug("convert plist to binary {}", it) - def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] - try { - commandRunner.run(commandList) - } catch (CommandRunnerException ex) { - logger.lifecycle("Unable to convert!") - } - } - } - - } - - - def removeResourceRules(File appDirectory) { - - File resourceRules = new File(appDirectory, "ResourceRules.plist") - logger.lifecycle("delete {}", resourceRules) - if (resourceRules.exists()) { - resourceRules.delete() - } - - logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) - - setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") - - } - - - File getArchiveDirectory() { - - def archiveDirectoryName = new File(PathHelper.resolveArchiveFolder(project), - getXcodeExtension().bundleName) - - if (project.xcodebuild.bundleNameSuffix != null) { - archiveDirectoryName += project.xcodebuild.bundleNameSuffix - } - archiveDirectoryName += ".xcarchive" - - def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) - archiveDirectory.mkdirs() - return archiveDirectory - } - - } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index be291de9..1e18cf24 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,15 +1,18 @@ package org.openbakery import groovy.transform.CompileStatic +import org.gradle.api.Task +import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild @CompileStatic @CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - public static final String TASK_NAME = "archive" + public static final String NAME = "xcodeBuildArchive" XcodeBuildArchiveTaskIosAndTvOS() { super() @@ -17,7 +20,15 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) - this.description = "Prepare the app bundle that it can be archive" + onlyIf(new Spec() { + @Override + boolean isSatisfiedBy(Task task) { + return getXcodeExtension().getType() == Type.iOS || + getXcodeExtension().getType() == Type.tvOS + } + }) + + this.description = "Use the xcodebuild archiver to create the project archive" } @InputFile diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy new file mode 100644 index 00000000..3afba448 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy @@ -0,0 +1,541 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openbakery + +import groovy.io.FileType +import org.apache.commons.io.FileUtils +import org.gradle.api.Task +import org.gradle.api.specs.Spec +import org.gradle.api.tasks.TaskAction +import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type +import org.openbakery.xcode.Extension +import org.openbakery.xcode.Xcodebuild + +import static groovy.io.FileType.FILES + +class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { + + public static final String NAME = "legacyArchive" + + XcodeBuildLegacyArchiveTask() { + super() + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME, + XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + + this.description = "Use the legacy archiver to create the project archive" + + onlyIf(new Spec() { + @Override + boolean isSatisfiedBy(Task task) { + return getXcodeExtension().getType() == Type.macOS || + getXcodeExtension().getType() == Type.watchOS + } + }) + } + + + def getOutputDirectory() { + def archiveDirectory = PathHelper.resolveArchiveFolder(project) + archiveDirectory.mkdirs() + return archiveDirectory + } + + + def getiOSIcons() { + ArrayList icons = new ArrayList<>(); + + File applicationBundle = parameters.applicationBundle + def fileList = applicationBundle.list( + [accept: { d, f -> f ==~ /Icon(-\d+)??\.png/ }] as FilenameFilter // matches Icon.png or Icon-72.png + ).toList() + + def applicationPath = "Applications/" + parameters.applicationBundleName + + for (String item in fileList) { + icons.add(applicationPath + "/" + item) + } + + + return icons + } + + def getMacOSXIcons() { + File appInfoPlist = new File(parameters.applicationBundle, "Contents/Info.plist") + ArrayList icons = new ArrayList<>(); + + def icnsFileName = plistHelper.getValueFromPlist(appInfoPlist, "CFBundleIconFile") + + if (icnsFileName == null || icnsFileName == "") { + return icons + } + + def iconPath = "Applications/" + parameters.applicationBundleName + "/Contents/Resources/" + icnsFileName + ".icns" + icons.add(iconPath) + + return icons + } + + + def getValueFromBundleInfoPlist(File bundle, String key) { + File appInfoPlist + if (parameters.type == Type.macOS) { + appInfoPlist = new File(bundle, "Contents/Info.plist") + } else { + appInfoPlist = new File(bundle, "Info.plist") + } + return plistHelper.getValueFromPlist(appInfoPlist, key) + } + + + def createInfoPlist(def applicationsDirectory) { + + StringBuilder content = new StringBuilder(); + + + def name = parameters.bundleName + def schemeName = name + def applicationPath = "Applications/" + parameters.applicationBundleName + def bundleIdentifier = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleIdentifier") + int time = System.currentTimeMillis() / 1000; + + def creationDate = formatDate(new Date()); + + def shortBundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleShortVersionString") + def bundleVersion = getValueFromBundleInfoPlist(parameters.applicationBundle, "CFBundleVersion") + + List icons + if (parameters.type == Type.iOS || parameters.type == Type.tvOS) { + icons = getiOSIcons() + } else { + icons = getMacOSXIcons() + } + + content.append("\n") + content.append("\n") + content.append("\n") + content.append("\n") + content.append(" ApplicationProperties\n") + content.append(" \n") + content.append(" ApplicationPath\n") + content.append(" " + applicationPath + "\n") + content.append(" CFBundleIdentifier\n") + content.append(" " + bundleIdentifier + "\n") + + if (shortBundleVersion != null) { + content.append(" CFBundleShortVersionString\n") + content.append(" " + shortBundleVersion + "\n") + } + + if (bundleVersion != null) { + content.append(" CFBundleVersion\n") + content.append(" " + bundleVersion + "\n") + } + + if (getSigningIdentity()) { + content.append(" SigningIdentity\n") + content.append(" " + getSigningIdentity() + "\n") + + } + + if (icons.size() > 0) { + content.append(" IconPaths\n") + content.append(" \n") + for (String icon : icons) { + content.append(" " + icon + "\n") + } + content.append(" \n") + } + + content.append(" \n") + content.append(" ArchiveVersion\n") + content.append(" 2\n") + content.append(" CreationDate\n") + content.append(" " + creationDate + "\n") + content.append(" Name\n") + content.append(" " + name + "\n") + content.append(" SchemeName\n") + content.append(" " + schemeName + "\n") + content.append("\n") + content.append("") + + File infoPlist = new File(applicationsDirectory, "Info.plist") + FileUtils.writeStringToFile(infoPlist, content.toString()) + } + + + def createFrameworks(def archiveDirectory, Xcodebuild xcodebuild) { + + File frameworksPath = new File(archiveDirectory, "Products/Applications/" + parameters.applicationBundleName + "/Frameworks") + if (frameworksPath.exists()) { + + + def libNames = [] + frameworksPath.eachFile() { + libNames.add(it.getName()) + } + + logger.debug("swiftlibs to add: {}", libNames); + + File swiftLibs = new File(xcodebuild.getToolchainDirectory(), + "usr/lib/swift/" + getSwiftLibFolderName()) + + logger.debug("swiftlibs to add: {}", swiftLibs); + + swiftLibs.eachFile() { + logger.debug("candidate for copy? {}: {}", it.name, libNames.contains(it.name)) + if (libNames.contains(it.name)) { + copy(it, getSwiftSupportDirectory()) + } + } + } + + } + + public String getSwiftLibFolderName() { + String result + switch (parameters.type) { + case Type.tvOS: + result = "appletvos" + break + + case Type.iOS: + result = "iphoneos" + break + + default: + break + } + + return result + } + + def getSwiftSupportDirectory() { + def swiftSupportPath = "SwiftSupport" + + if (xcode.version.major > 6) { + swiftSupportPath += "/" + getSwiftLibFolderName() + } + + File swiftSupportDirectory = new File(getArchiveDirectory(), swiftSupportPath) + if (!swiftSupportDirectory.exists()) { + swiftSupportDirectory.mkdirs() + } + return swiftSupportDirectory + } + + def deleteDirectoryIfEmpty(File base, String child) { + File directory = new File(base, child) + if (directory.exists() && directory.list().length == 0) { + directory.deleteDir(); + } + } + + def deleteEmptyFrameworks(File applicationsDirectory) { + // if frameworks directory is emtpy + File appPath = new File(applicationsDirectory, "Products/Applications/" + parameters.applicationBundleName) + deleteDirectoryIfEmpty(appPath, "Frameworks") + + + } + + def deleteFrameworksInExtension(File applicationsDirectory) { + + + File plugins = new File(applicationsDirectory, parameters.applicationBundleName + "/Plugins") + if (!plugins.exists()) { + return + } + + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith(".appex")) { + File frameworkDirectory = new File(file, "Frameworks"); + if (frameworkDirectory.exists()) { + FileUtils.deleteDirectory(frameworkDirectory) + } + } + } + + } + + + def copyDsyms(File archiveDirectory, File dSymDirectory) { + + archiveDirectory.eachFileRecurse(FileType.DIRECTORIES) { directory -> + if (directory.toString().toLowerCase().endsWith(".dsym")) { + copy(directory, dSymDirectory) + } + } + + } + + def createEntitlements(File bundle) { + + if (parameters.type != Type.iOS && parameters.type != Type.tvOS) { + logger.warn("Entitlements handling is only implemented for iOS and tvOS!") + return + } + + String bundleIdentifier = getValueFromBundleInfoPlist(bundle, "CFBundleIdentifier") + if (bundleIdentifier == null) { + logger.debug("No entitlements embedded, because no bundle identifier found in bundle {}", bundle) + return + } + BuildConfiguration buildConfiguration = project.xcodebuild.getBuildConfiguration(bundleIdentifier) + if (buildConfiguration == null) { + logger.debug("No entitlements embedded, because no buildConfiguration for bundle identifier {}", bundleIdentifier) + return + } + + File destinationDirectory = getDestinationDirectoryForBundle(bundle) + if (buildConfiguration.entitlements) { + File entitlementFile = new File(destinationDirectory, "archived-expanded-entitlements.xcent") + FileUtils.copyFile(new File(project.projectDir, buildConfiguration.entitlements), entitlementFile) + modifyEntitlementsFile(entitlementFile, bundleIdentifier) + } + } + + def modifyEntitlementsFile(File entitlementFile, String bundleIdentifier) { + if (!entitlementFile.exists()) { + logger.warn("Entitlements File does not exist {}", entitlementFile) + return + } + + String applicationIdentifier = "UNKNOWN00ID"; + // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback + File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) + if (provisioningProfile != null && provisioningProfile.exists()) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) + applicationIdentifier = reader.getApplicationIdentifierPrefix() + } + + plistHelper.addValueForPlist(entitlementFile, "application-identifier", applicationIdentifier + "." + bundleIdentifier) + + List keychainAccessGroups = plistHelper.getValueFromPlist(entitlementFile, "keychain-access-groups") + + if (keychainAccessGroups != null && keychainAccessGroups.size() > 0) { + def modifiedKeychainAccessGroups = [] + keychainAccessGroups.each() { group -> + modifiedKeychainAccessGroups << group.replace(ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX, applicationIdentifier + ".") + } + plistHelper.setValueForPlist(entitlementFile, "keychain-access-groups", modifiedKeychainAccessGroups) + } + } + + def createExtensionSupportDirectory(File bundle, Xcodebuild xcodebuild) { + String extensionIdentifier = getValueFromBundleInfoPlist(bundle, "NSExtension:NSExtensionPointIdentifier") + if (extensionIdentifier == null) { + logger.debug("No support directory created, because no extension identifier found in bundle {}", bundle) + return + } + + Extension extension = Extension.extensionFromIdentifier(extensionIdentifier) + if (extension == null) { + logger.warn("Extension type not supported", extensionIdentifier) + return + } + + switch (extension) { + case Extension.sticker: + File supportDirectory = new File(getArchiveDirectory(), "MessagesApplicationExtensionSupport") + if (supportDirectory.mkdirs()) { + File stub = new File(xcodebuild.getPlatformDirectory(), "/Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub") + copy(stub, supportDirectory) + } + break + default: + break + } + } + + @TaskAction + def archive() { + println "archive" + parameters = project.xcodebuild.xcodebuildParameters.merge(parameters) + if (parameters.isSimulatorBuildOf(Type.iOS) || parameters.isSimulatorBuildOf(Type.tvOS)) { + logger.debug("Create zip archive") + + // create zip archive + String zipFileName = parameters.bundleName + if (project.xcodebuild.bundleNameSuffix != null) { + zipFileName += project.xcodebuild.bundleNameSuffix + } + zipFileName += ".zip" + + def zipFile = new File(project.getBuildDir(), "archive/" + zipFileName) + def baseDirectory = parameters.applicationBundle.parentFile + + createZip(zipFile, baseDirectory, parameters.applicationBundle) + return + } + + logger.debug("Create xcarchive") + Xcodebuild xcodebuild = new Xcodebuild(project.projectDir, commandRunner, xcode, parameters, getDestinations()) + + if (project.xcodebuild.useXcodebuildArchive) { + + File outputFile = new File(project.getBuildDir(), "xcodebuild-archive-output.txt") + commandRunner.setOutputFile(outputFile) + + xcodebuild.executeArchive(createXcodeBuildOutputAppender("XcodeBuildArchive"), project.xcodebuild.environment, getArchiveDirectory().absolutePath) + + return + } + + // create xcarchive + // copy application bundle + copy(parameters.applicationBundle, getApplicationsDirectory()) + + File onDemandResources = new File(parameters.outputPath, "OnDemandResources") + if (onDemandResources.exists()) { + copy(onDemandResources, getProductsDirectory()) + } + + // copy onDemandResources + + def dSymDirectory = new File(getArchiveDirectory(), "dSYMs") + dSymDirectory.mkdirs() + copyDsyms(parameters.outputPath, dSymDirectory) + + List appBundles = getAppBundles(parameters.outputPath) + for (File bundle : appBundles) { + createEntitlements(bundle) + createExtensionSupportDirectory(bundle, xcodebuild) + } + + File applicationsDirectory = getApplicationsDirectory() + + File archiveDirectory = getArchiveDirectory() + createInfoPlist(archiveDirectory) + createFrameworks(archiveDirectory, xcodebuild) + deleteEmptyFrameworks(archiveDirectory) + deleteXCTestIfExists(applicationsDirectory) + deleteFrameworksInExtension(applicationsDirectory) + copyBCSymbolMaps(archiveDirectory) + + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { + File applicationFolder = new File(getArchiveDirectory(), "Products/Applications/" + parameters.applicationBundleName) + convertInfoPlistToBinary(applicationFolder) + + removeUnneededDylibsFromBundle(applicationFolder) + } + + logger.debug("create archive done") + } + + def copyBCSymbolMaps(File archiveDirectory) { + if (!parameters.bitcode) { + logger.debug("bitcode is not activated, so to not create BCSymbolMaps") + return + } + File bcSymbolMapsDirectory = new File(archiveDirectory, "BCSymbolMaps") + bcSymbolMapsDirectory.mkdirs() + + parameters.outputPath.eachFileRecurse { file -> + if (file.toString().endsWith(".bcsymbolmap")) { + FileUtils.copyFileToDirectory(file, bcSymbolMapsDirectory) + } + } + + } + + // TODO: Define a `exportOptionsPlist` to avoid that kind of issue + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } + + def deleteXCTestIfExists(File applicationsDirectory) { + File plugins = new File(applicationsDirectory, project.xcodebuild.applicationBundle.name + "/Contents/Plugins") + if (!plugins.exists()) { + return + } + plugins.eachFile(FileType.DIRECTORIES) { file -> + if (file.toString().endsWith("xctest")) { + FileUtils.deleteDirectory(file) + return true + } + } + } + + File getProductsDirectory() { + File productsDirectory = new File(getArchiveDirectory(), "Products") + productsDirectory.mkdirs() + return productsDirectory + } + + File getApplicationsDirectory() { + File applicationsDirectory = new File(getProductsDirectory(), "Applications") + applicationsDirectory.mkdirs() + return applicationsDirectory + } + + File getDestinationDirectoryForBundle(File bundle) { + String relative = parameters.outputPath.toURI().relativize(bundle.toURI()).getPath(); + return new File(getApplicationsDirectory(), relative) + } + + def convertInfoPlistToBinary(File archiveDirectory) { + + archiveDirectory.eachFileRecurse(FILES) { + if (it.name.endsWith('.plist')) { + logger.debug("convert plist to binary {}", it) + def commandList = ["/usr/bin/plutil", "-convert", "binary1", it.absolutePath] + try { + commandRunner.run(commandList) + } catch (CommandRunnerException ex) { + logger.lifecycle("Unable to convert!") + } + } + } + + } + + + def removeResourceRules(File appDirectory) { + + File resourceRules = new File(appDirectory, "ResourceRules.plist") + logger.lifecycle("delete {}", resourceRules) + if (resourceRules.exists()) { + resourceRules.delete() + } + + logger.lifecycle("remove CFBundleResourceSpecification from {}", new File(appDirectory, "Info.plist")) + + setValueForPlist(new File(appDirectory, "Info.plist"), "Delete: CFBundleResourceSpecification") + + } + + + File getArchiveDirectory() { + def archiveDirectoryName = PathHelper.FOLDER_ARCHIVE + "/" + project.xcodebuild.bundleName + + if (project.xcodebuild.bundleNameSuffix != null) { + archiveDirectoryName += project.xcodebuild.bundleNameSuffix + } + archiveDirectoryName += ".xcarchive" + + def archiveDirectory = new File(project.getBuildDir(), archiveDirectoryName) + archiveDirectory.mkdirs() + return archiveDirectory + } + + +} diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index e1216dd5..ce510fed 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -433,6 +433,9 @@ class XcodeBuildPluginExtension { this.type = Type.typeFromString(type) } + Type getType() { + return type + } boolean getSimulator() { if (type == Type.macOS) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index c60d9045..0c512261 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -461,21 +461,21 @@ class XcodePlugin implements Plugin { } private void configureArchive(Project project) { - if (project.xcodebuild.type == Type.tvOS - || project.xcodebuild.type == Type.iOS) { - PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.tasks.create( - PrepareXcodeArchivingTask.NAME, - PrepareXcodeArchivingTask.class) - prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) - - XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.tasks.create( - XcodeBuildArchiveTaskIosAndTvOS.TASK_NAME, - XcodeBuildArchiveTaskIosAndTvOS.class) - archiveTask.setGroup(XCODE_GROUP_NAME) - } else { - XcodeBuildArchiveTask xcodeBuildArchiveTask = project.getTasks().create(ARCHIVE_TASK_NAME, XcodeBuildArchiveTask.class); - xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME); - } + PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.getTasks(). + create(PrepareXcodeArchivingTask.NAME, PrepareXcodeArchivingTask.class) + prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) + + XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.getTasks(). + create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) + archiveTask.setGroup(XCODE_GROUP_NAME) + + XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask = project.getTasks(). + create(XcodeBuildLegacyArchiveTask.NAME, XcodeBuildLegacyArchiveTask.class) + xcodeBuildArchiveTask.setGroup(XCODE_GROUP_NAME) + + XcodeBuildArchiveTask task = project.tasks.create(XcodeBuildArchiveTask.NAME, + XcodeBuildArchiveTask.class) + task.setGroup(XCODE_GROUP_NAME) //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); } diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy index 961ae033..e6ea52ca 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy @@ -12,7 +12,7 @@ class XcodeBuildArchiveTaskOSXSpecification extends Specification { Project project - XcodeBuildArchiveTask xcodeBuildArchiveTask; + XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask; File projectDir File buildOutputDirectory diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy index f84d1752..18d800b3 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy @@ -23,7 +23,7 @@ class XcodeBuildArchiveTaskSpecification extends Specification { Project project - XcodeBuildArchiveTask xcodeBuildArchiveTask + XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask File projectDir File buildOutputDirectory diff --git a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy index 463729a4..d6c19d86 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy @@ -46,7 +46,7 @@ class XcodePluginSpecification extends Specification { def "contain task archive"() { expect: - project.tasks.findByName('archive') instanceof XcodeBuildArchiveTask + project.tasks.findByName('archive') instanceof XcodeBuildLegacyArchiveTask } From d8ca4ac283cec9d5afd876825cc365bfdc5ce66a Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 14:49:08 +0100 Subject: [PATCH 063/121] Rename archive tasks --- .../main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy | 2 ++ .../org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy | 6 +++--- .../org/openbakery/XcodeBuildLegacyArchiveTask.groovy | 2 +- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 2 -- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy index 3eee7d58..97d0cb8a 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy @@ -9,5 +9,7 @@ class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { dependsOn(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildLegacyArchiveTask.NAME) + + setDescription("Archive and export the project") } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy index 1e18cf24..b7ac1087 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -12,7 +12,7 @@ import org.openbakery.xcode.Xcodebuild @CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { - public static final String NAME = "xcodeBuildArchive" + public static final String NAME = "archiveXcodeBuild" XcodeBuildArchiveTaskIosAndTvOS() { super() @@ -20,6 +20,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) + this.description = "Use the xcodebuild archiver to create the project archive" + onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { @@ -27,8 +29,6 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { getXcodeExtension().getType() == Type.tvOS } }) - - this.description = "Use the xcodebuild archiver to create the project archive" } @InputFile diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy index 3afba448..ee1c0be1 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy @@ -30,7 +30,7 @@ import static groovy.io.FileType.FILES class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { - public static final String NAME = "legacyArchive" + public static final String NAME = "archiveLegacy" XcodeBuildLegacyArchiveTask() { super() diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 0c512261..c42d080f 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -476,8 +476,6 @@ class XcodePlugin implements Plugin { XcodeBuildArchiveTask task = project.tasks.create(XcodeBuildArchiveTask.NAME, XcodeBuildArchiveTask.class) task.setGroup(XCODE_GROUP_NAME) - - //xcodeBuildArchiveTask.dependsOn(project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME)); } private void configureSimulatorTasks(Project project) { From 8ebfe73993ebaf01567e9fa64035089117c5de98 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 15:00:47 +0100 Subject: [PATCH 064/121] Use the path resolver --- .../src/main/groovy/org/openbakery/util/PathHelper.groovy | 2 +- .../groovy/org/openbakery/AbstractDistributeTask.groovy | 4 +--- .../main/groovy/org/openbakery/packaging/PackageTask.groovy | 3 ++- .../groovy/org/openbakery/packaging/ReleaseNotesTask.groovy | 6 +++--- .../openbakery/packaging/PackageTaskSpecification.groovy | 2 +- .../packaging/PackageTask_OSXSpecification.groovy | 2 +- .../packaging/PackageTask_WatchAppSpecification.groovy | 2 +- .../packaging/PackageTask_WatchKitSpecification.groovy | 2 +- 8 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index da606db0..c7ae4be7 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -11,9 +11,9 @@ class PathHelper { public static final String IPHONE_SIMULATOR = "iphonesimulator" public static final String IPHONE_OS = "iphoneos" public static final String FOLDER_ARCHIVE = "archive" + public static final String FOLDER_PACKAGE = "package" private static final String ARCHIVE_FILE_NAME = "archive.xcconfig" - private static final String FOLDER_PACKAGE = "package" private static final String EXTENSION_XC_ARCHIVE = ".xcarchive" static File resolvePath(Type type, diff --git a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy index 14c408f3..a0120cb1 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractDistributeTask.groovy @@ -1,11 +1,9 @@ package org.openbakery import org.apache.commons.io.FileUtils -import org.openbakery.packaging.PackageTask import org.openbakery.util.PathHelper import java.util.regex.Pattern - /** * User: rene * Date: 11/11/14 @@ -90,7 +88,7 @@ class AbstractDistributeTask extends AbstractXcodeBuildTask { } File getBundle(String extension) { - File packageDirectory = new File(project.getBuildDir(), PackageTask.PACKAGE_PATH) + File packageDirectory = PathHelper.resolvePackageFolder(project) if (!packageDirectory.exists()) { throw new IllegalStateException("package does not exist: " + packageDirectory) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index 3afbd362..fa9d1df5 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -10,6 +10,7 @@ import org.openbakery.CommandRunnerException import org.openbakery.bundle.ApplicationBundle import org.openbakery.codesign.Codesign import org.openbakery.codesign.CodesignParameters +import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader @@ -50,7 +51,7 @@ class PackageTask extends AbstractDistributeTask { logger.lifecycle("not a device build, so no codesign and packaging needed") return } - outputPath = new File(project.getBuildDir(), PACKAGE_PATH) + outputPath = PathHelper.resolvePackageFolder(project) File applicationFolder = createApplicationFolder() diff --git a/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy index e61856d7..96a8202f 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy @@ -18,7 +18,7 @@ package org.openbakery.packaging import org.apache.commons.io.FileUtils import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction - +import org.openbakery.util.PathHelper import org.pegdown.PegDownProcessor @@ -29,7 +29,7 @@ import org.pegdown.PegDownProcessor */ class ReleaseNotesTask extends DefaultTask { - File outputPath = new File(project.getBuildDir(), PackageTask.PACKAGE_PATH) + File outputPath = PathHelper.resolvePackageFolder(project) ReleaseNotesTask() { @@ -59,4 +59,4 @@ class ReleaseNotesTask extends DefaultTask { println "No changelog found!" } } -} \ No newline at end of file +} diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 9f43b242..c4cbb4c2 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -85,7 +85,7 @@ class PackageTaskSpecification extends Specification { } void mockExampleApp(boolean withPlugin, boolean withSwift, boolean withFramework = false, boolean adHoc = true, boolean bitcode = false) { - outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) + outputPath = PathHelper.resolvePackageFolder(project) archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy index 130dcb60..b0d7b92f 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy @@ -67,7 +67,7 @@ class PackageTask_OSXSpecification extends Specification { archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") - outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) + outputPath = PathHelper.resolvePackageFolder(project) appDirectory = new File(outputPath, "Example.app"); diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy index c140b01a..1427baab 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy @@ -59,7 +59,7 @@ class PackageTask_WatchAppSpecification extends Specification { archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") - outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) + outputPath = PathHelper.resolvePackageFolder(project) File payloadDirectory = new File(outputPath, "Payload") payloadAppDirectory = new File(payloadDirectory, "ExampleWatchKit.app"); diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy index 6e421aa9..dc4f6219 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy @@ -55,7 +55,7 @@ class PackageTask_WatchKitSpecification extends Specification { archiveDirectory = new File(PathHelper.resolveArchiveFolder(project), "Example.xcarchive") - outputPath = new File(project.getBuildDir(), packageTask.PACKAGE_PATH) + outputPath = PathHelper.resolvePackageFolder(project) File payloadDirectory = new File(outputPath, "Payload") payloadAppDirectory = new File(payloadDirectory, "Example.app"); From d58519a408675849e5a312707f0af0bce888c873 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 15:20:46 +0100 Subject: [PATCH 065/121] Same for packager' --- .../groovy/org/openbakery/XcodePlugin.groovy | 44 ++- .../crashlytics/CrashlyticsUploadTask.groovy | 6 +- .../packaging/PackageLegacyTask.groovy | 336 ++++++++++++++++++ .../openbakery/packaging/PackageTask.groovy | 318 +---------------- .../packaging/PackageTaskIosAndTvOS.groovy | 13 +- ...AbstractDistributeTaskSpecification.groovy | 3 +- .../packaging/PackageTaskSpecification.groovy | 4 +- .../PackageTask_OSXSpecification.groovy | 5 +- .../PackageTask_WatchAppSpecification.groovy | 5 +- .../PackageTask_WatchKitSpecification.groovy | 5 +- ...visioningProfileReaderSpecification.groovy | 11 +- 11 files changed, 397 insertions(+), 353 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index c42d080f..dbf5580f 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -48,12 +48,12 @@ import org.openbakery.hockeyapp.HockeyAppUploadTask import org.openbakery.hockeykit.* import org.openbakery.oclint.OCLintPluginExtension import org.openbakery.oclint.OCLintTask +import org.openbakery.packaging.PackageLegacyTask import org.openbakery.packaging.PackageTask import org.openbakery.packaging.PackageTaskIosAndTvOS import org.openbakery.packaging.ReleaseNotesTask import org.openbakery.signing.* import org.openbakery.simulators.* -import org.openbakery.xcode.Type import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -101,7 +101,6 @@ class XcodePlugin implements Plugin { public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' - public static final String PACKAGE_TASK_NAME = 'package' public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' @@ -522,22 +521,17 @@ class XcodePlugin implements Plugin { } private configurePackage(Project project) { - if (project.xcodebuild.type == Type.tvOS - || project.xcodebuild.type == Type.iOS) { - project.task(PackageTaskIosAndTvOS.TASK_NAME, - type: PackageTaskIosAndTvOS, - group: XCODE_GROUP_NAME) - - } else { - PackageTask packageTask = project.task(PACKAGE_TASK_NAME, - type: PackageTask, - group: XCODE_GROUP_NAME) - - XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) - packageTask.shouldRunAfter(xcodeBuildTask) - } + configureModernPackager(project) + configureLegacyPackager(project) + + project.task(PackageTask.NAME, + type: PackageTask.class, + group: XCODE_GROUP_NAME) + + project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, + type: ReleaseNotesTask, + group: XCODE_GROUP_NAME) - project.task(PACKAGE_RELEASE_NOTES_TASK_NAME, type: ReleaseNotesTask, group: XCODE_GROUP_NAME) //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) @@ -550,6 +544,22 @@ class XcodePlugin implements Plugin { */ } + private void configureModernPackager(Project project) { + project.task(PackageTaskIosAndTvOS.NAME, + type: PackageTaskIosAndTvOS, + group: XCODE_GROUP_NAME) + } + + private void configureLegacyPackager(Project project) { + PackageLegacyTask packageTask = project.task(PackageLegacyTask.NAME, + type: PackageLegacyTask, + group: XCODE_GROUP_NAME) + + XcodeBuildTask xcodeBuildTask = project.getTasks().getByName(XCODE_BUILD_TASK_NAME) + packageTask.shouldRunAfter(xcodeBuildTask) + } + + private configureAppstore(Project project) { project.task(APPSTORE_UPLOAD_TASK_NAME, type: AppstoreUploadTask, group: APPSTORE_GROUP_NAME) project.task(APPSTORE_VALIDATE_TASK_NAME, type: AppstoreValidateTask, group: APPSTORE_GROUP_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/crashlytics/CrashlyticsUploadTask.groovy b/plugin/src/main/groovy/org/openbakery/crashlytics/CrashlyticsUploadTask.groovy index 3b648510..2a750d29 100755 --- a/plugin/src/main/groovy/org/openbakery/crashlytics/CrashlyticsUploadTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/crashlytics/CrashlyticsUploadTask.groovy @@ -19,14 +19,14 @@ import org.gradle.api.tasks.TaskAction import org.gradle.internal.logging.text.StyledTextOutput import org.gradle.internal.logging.text.StyledTextOutputFactory import org.openbakery.AbstractDistributeTask -import org.openbakery.XcodePlugin import org.openbakery.output.ConsoleOutputAppender +import org.openbakery.packaging.PackageTask class CrashlyticsUploadTask extends AbstractDistributeTask { CrashlyticsUploadTask() { super() - dependsOn(XcodePlugin.PACKAGE_TASK_NAME) + dependsOn(PackageTask.NAME) this.description = "Upload the IPA to crashlytics for crash reports" } @@ -86,4 +86,4 @@ class CrashlyticsUploadTask extends AbstractDistributeTask { } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy new file mode 100644 index 00000000..2817de2e --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy @@ -0,0 +1,336 @@ +package org.openbakery.packaging + +import org.apache.commons.io.FileUtils +import org.apache.commons.io.FilenameUtils +import org.gradle.api.Task +import org.gradle.api.specs.Spec +import org.gradle.api.tasks.TaskAction +import org.gradle.internal.logging.text.StyledTextOutput +import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.openbakery.AbstractDistributeTask +import org.openbakery.CommandRunnerException +import org.openbakery.bundle.ApplicationBundle +import org.openbakery.codesign.Codesign +import org.openbakery.codesign.CodesignParameters +import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type +import org.openbakery.XcodePlugin +import org.openbakery.codesign.ProvisioningProfileReader + +class PackageLegacyTask extends AbstractDistributeTask { + + public static final String NAME = "packageLegacy" + + public static final String PACKAGE_PATH = "package" + File outputPath + + + private List appBundles + + String applicationBundleName + StyledTextOutput output + + + CodesignParameters codesignParameters = new CodesignParameters() + + PackageLegacyTask() { + super() + setDescription("Signs the app bundle that was created by the build and creates the ipa") + dependsOn( + XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, + XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, + ) + + finalizedBy( + XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME + ) + + onlyIf(new Spec() { + @Override + boolean isSatisfiedBy(Task task) { + return getXcodeExtension().getType() == Type.watchOS || + getXcodeExtension().getType() == Type.macOS + } + }) + + output = services.get(StyledTextOutputFactory).create(PackageLegacyTask) + + } + + + @TaskAction + void packageApplication() throws IOException { + if (project.xcodebuild.isSimulatorBuildOf(Type.iOS) || project.xcodebuild.isSimulatorBuildOf(Type.tvOS)) { + logger.lifecycle("not a device build, so no codesign and packaging needed") + return + } + outputPath = PathHelper.resolvePackageFolder(project) + + File applicationFolder = createApplicationFolder() + + def applicationName = getApplicationNameFromArchive() + copy(getApplicationBundleDirectory(), applicationFolder) + + applicationBundleName = applicationName + ".app" + + File applicationPath = new File(applicationFolder, applicationBundleName) + + // copy onDemandResources + File onDemandResources = new File(getProductsDirectory(), "OnDemandResources") + if (onDemandResources.exists()) { + copy(onDemandResources, applicationPath) + } + + File bcSymbolsMaps = new File(getArchiveDirectory(), "BCSymbolMaps") + if (bcSymbolsMaps.exists()) { + copy(bcSymbolsMaps, applicationFolder.parentFile) + } + + enumerateExtensionSupportDirectories(getArchiveDirectory()) { File supportDirectory -> + copy(supportDirectory, applicationFolder.parentFile) + } + + ApplicationBundle applicationBundle = new ApplicationBundle(applicationPath , project.xcodebuild.type, project.xcodebuild.simulator) + appBundles = applicationBundle.getBundles() + + File resourceRules = new File(applicationFolder, applicationBundleName + "/ResourceRules.plist") + if (resourceRules.exists()) { + resourceRules.delete() + } + + + File infoPlist = getInfoPlistFile() + + try { + plistHelper.deleteValueFromPlist(infoPlist, "CFBundleResourceSpecification") + } catch (CommandRunnerException ex) { + // ignore, this means that the CFBundleResourceSpecification was not in the infoPlist + } + + def signSettingsAvailable = true + if (project.xcodebuild.signing.mobileProvisionFile == null) { + logger.warn('No mobile provision file provided.') + signSettingsAvailable = false; + } else if (!project.xcodebuild.signing.keychainPathInternal.exists()) { + logger.warn('No certificate or keychain found.') + signSettingsAvailable = false; + } + + codesignParameters.mergeMissing(project.xcodebuild.signing.codesignParameters) + codesignParameters.type = project.xcodebuild.type + codesignParameters.keychain = project.xcodebuild.signing.keychainPathInternal + Codesign codesign = new Codesign(xcode, codesignParameters, commandRunner, plistHelper) + + for (File bundle : appBundles) { + + if (isDeviceBuildiOStvOS()) { + removeFrameworkFromExtensions(bundle) + removeUnneededDylibsFromBundle(bundle) + embedProvisioningProfileToBundle(bundle) + } + + if (signSettingsAvailable) { + logger.info("Codesign app: {}", bundle) + codesign.sign(bundle) + } else { + String message = "Bundle not signed: " + bundle + output.withStyle(StyledTextOutput.Style.Failure).println(message) + } + } + + File appBundle = appBundles.last() + if (isDeviceBuildiOStvOS()) { + + boolean isAdHoc = isAdHoc(appBundle) + createIpa(applicationFolder, !isAdHoc) + } else { + createPackage(appBundle) + } + + } + + boolean isDeviceBuildiOStvOS() { + return project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS) + } + + boolean isAdHoc(File appBundle) { + File provisionFile = getProvisionFileForBundle(appBundle) + if (provisionFile == null) { + return false + } + ProvisioningProfileReader reader = new ProvisioningProfileReader(provisionFile, this.commandRunner, this.plistHelper) + return reader.isAdHoc() + } + + def removeFrameworkFromExtensions(File bundle) { + // appex extensions should not contain extensions + if (FilenameUtils.getExtension(bundle.toString()).equalsIgnoreCase("appex")) { + File frameworksPath = new File(bundle, "Frameworks") + if (frameworksPath.exists()) { + FileUtils.deleteDirectory(frameworksPath) + } + } + + } + + def removeUnneededDylibsFromBundle(File bundle) { + File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") + if (libswiftRemoteMirror.exists()) { + libswiftRemoteMirror.delete() + } + } + + File getProvisionFileForBundle(File bundle) { + String bundleIdentifier = getIdentifierForBundle(bundle) + return ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) + } + + + def addSwiftSupport(File payloadPath, String applicationBundleName) { + File frameworksPath = new File(payloadPath, applicationBundleName + "/Frameworks") + if (!frameworksPath.exists()) { + return null + } + + File swiftLibArchive = new File(getArchiveDirectory(), "SwiftSupport") + + if (swiftLibArchive.exists()) { + copy(swiftLibArchive, payloadPath.getParentFile()) + return new File(payloadPath.getParentFile(), "SwiftSupport") + } + return null + } + + + private void createZipPackage(File packagePath, String extension, boolean includeSwiftSupport) { + File packageBundle = new File(outputPath, getIpaFileName() + "." + extension) + if (!packageBundle.parentFile.exists()) { + packageBundle.parentFile.mkdirs() + } + + List filesToZip = [] + filesToZip << packagePath + + if (includeSwiftSupport) { + File swiftSupportPath = addSwiftSupport(packagePath, applicationBundleName) + if (swiftSupportPath != null) { + filesToZip << swiftSupportPath + } + } + + File bcSymbolMapsPath = new File(packagePath.getParentFile(), "BCSymbolMaps") + if (bcSymbolMapsPath.exists()) { + filesToZip << bcSymbolMapsPath + } + + enumerateExtensionSupportDirectories(packagePath.getParentFile()) { File supportDirectory -> + filesToZip << supportDirectory + } + + createZip(packageBundle, packagePath.getParentFile(), packagePath, *filesToZip) + } + + private void enumerateExtensionSupportDirectories(File parentDirectory, Closure closure) { + def directoryNames = ["MessagesApplicationExtensionSupport"] + + for (String name in directoryNames) { + File supportDirectory = new File(parentDirectory, name) + if (supportDirectory.exists()) { + closure(supportDirectory) + } + } + } + + private void createIpa(File payloadPath, boolean addSwiftSupport) { + createZipPackage(payloadPath, "ipa", addSwiftSupport) + } + + private void createPackage(File packagePath) { + + createZipPackage(packagePath, "zip", false) + } + + + private String getIdentifierForBundle(File bundle) { + File infoPlist + + if (isDeviceBuildiOStvOS()) { + infoPlist = new File(bundle, "Info.plist"); + } else { + infoPlist = new File(bundle, "Contents/Info.plist") + } + + String bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") + return bundleIdentifier + } + + + private void embedProvisioningProfileToBundle(File bundle) { + File mobileProvisionFile = getProvisionFileForBundle(bundle) + if (mobileProvisionFile != null) { + File embeddedProvisionFile + + String profileExtension = FilenameUtils.getExtension(mobileProvisionFile.absolutePath) + embeddedProvisionFile = new File(getAppContentPath(bundle) + "embedded." + profileExtension) + + logger.info("provision profile - {}", embeddedProvisionFile) + + FileUtils.copyFile(mobileProvisionFile, embeddedProvisionFile) + } + } + + private File createSigningDestination(String name) throws IOException { + File destination = new File(outputPath, name) + if (destination.exists()) { + FileUtils.deleteDirectory(destination) + } + destination.mkdirs(); + return destination; + } + + private File createApplicationFolder() throws IOException { + + if (isDeviceBuildiOStvOS()) { + return createSigningDestination("Payload") + } else { + // same folder as signing + if (!outputPath.exists()) { + outputPath.mkdirs() + } + return outputPath + } + } + + private File getInfoPlistFile() { + return new File(getAppContentPath() + "Info.plist") + } + + private String getAppContentPath() { + + return getAppContentPath(appBundles.last()) + } + + private String getAppContentPath(File bundle) { + if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { + return bundle.absolutePath + "/" + } + return bundle.absolutePath + "/Contents/" + } + + def getIpaFileName() { + if (project.xcodebuild.ipaFileName) { + return project.xcodebuild.ipaFileName + } else { + return getApplicationNameFromArchive() + } + } + + + String getSigningIdentity() { + return codesignParameters.signingIdentity + } + + void setSigningIdentity(String identity) { + codesignParameters.signingIdentity = identity + } +} diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index fa9d1df5..1a2553b9 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -1,323 +1,15 @@ package org.openbakery.packaging -import org.apache.commons.io.FileUtils -import org.apache.commons.io.FilenameUtils -import org.gradle.api.tasks.TaskAction -import org.gradle.internal.logging.text.StyledTextOutput -import org.gradle.internal.logging.text.StyledTextOutputFactory -import org.openbakery.AbstractDistributeTask -import org.openbakery.CommandRunnerException -import org.openbakery.bundle.ApplicationBundle -import org.openbakery.codesign.Codesign -import org.openbakery.codesign.CodesignParameters -import org.openbakery.util.PathHelper -import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin -import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.AbstractXcodeBuildTask -class PackageTask extends AbstractDistributeTask { +class PackageTask extends AbstractXcodeBuildTask { - public static final String PACKAGE_PATH = "package" - File outputPath - - - private List appBundles - - String applicationBundleName - StyledTextOutput output - - - CodesignParameters codesignParameters = new CodesignParameters() + public static final String NAME = "package" PackageTask() { super() - setDescription("Signs the app bundle that was created by the build and creates the ipa") - dependsOn( - XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, - XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, - ) - finalizedBy( - XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME - ) - - output = services.get(StyledTextOutputFactory).create(PackageTask) - - } - - - @TaskAction - void packageApplication() throws IOException { - if (project.xcodebuild.isSimulatorBuildOf(Type.iOS) || project.xcodebuild.isSimulatorBuildOf(Type.tvOS)) { - logger.lifecycle("not a device build, so no codesign and packaging needed") - return - } - outputPath = PathHelper.resolvePackageFolder(project) - - File applicationFolder = createApplicationFolder() - - def applicationName = getApplicationNameFromArchive() - copy(getApplicationBundleDirectory(), applicationFolder) - - applicationBundleName = applicationName + ".app" - - File applicationPath = new File(applicationFolder, applicationBundleName) - - // copy onDemandResources - File onDemandResources = new File(getProductsDirectory(), "OnDemandResources") - if (onDemandResources.exists()) { - copy(onDemandResources, applicationPath) - } - - File bcSymbolsMaps = new File(getArchiveDirectory(), "BCSymbolMaps") - if (bcSymbolsMaps.exists()) { - copy(bcSymbolsMaps, applicationFolder.parentFile) - } - - enumerateExtensionSupportDirectories(getArchiveDirectory()) { File supportDirectory -> - copy(supportDirectory, applicationFolder.parentFile) - } - - ApplicationBundle applicationBundle = new ApplicationBundle(applicationPath , project.xcodebuild.type, project.xcodebuild.simulator) - appBundles = applicationBundle.getBundles() - - File resourceRules = new File(applicationFolder, applicationBundleName + "/ResourceRules.plist") - if (resourceRules.exists()) { - resourceRules.delete() - } - - - File infoPlist = getInfoPlistFile() - - try { - plistHelper.deleteValueFromPlist(infoPlist, "CFBundleResourceSpecification") - } catch (CommandRunnerException ex) { - // ignore, this means that the CFBundleResourceSpecification was not in the infoPlist - } - - def signSettingsAvailable = true - if (project.xcodebuild.signing.mobileProvisionFile == null) { - logger.warn('No mobile provision file provided.') - signSettingsAvailable = false; - } else if (!project.xcodebuild.signing.keychainPathInternal.exists()) { - logger.warn('No certificate or keychain found.') - signSettingsAvailable = false; - } - - codesignParameters.mergeMissing(project.xcodebuild.signing.codesignParameters) - codesignParameters.type = project.xcodebuild.type - codesignParameters.keychain = project.xcodebuild.signing.keychainPathInternal - Codesign codesign = new Codesign(xcode, codesignParameters, commandRunner, plistHelper) - - for (File bundle : appBundles) { - - if (isDeviceBuildiOStvOS()) { - removeFrameworkFromExtensions(bundle) - removeUnneededDylibsFromBundle(bundle) - embedProvisioningProfileToBundle(bundle) - } - - if (signSettingsAvailable) { - logger.info("Codesign app: {}", bundle) - codesign.sign(bundle) - } else { - String message = "Bundle not signed: " + bundle - output.withStyle(StyledTextOutput.Style.Failure).println(message) - } - } - - File appBundle = appBundles.last() - if (isDeviceBuildiOStvOS()) { - - boolean isAdHoc = isAdHoc(appBundle) - createIpa(applicationFolder, !isAdHoc) - } else { - createPackage(appBundle) - } - - } - - boolean isDeviceBuildiOStvOS() { - return project.xcodebuild.isDeviceBuildOf(Type.iOS) || project.xcodebuild.isDeviceBuildOf(Type.tvOS) - } - - boolean isAdHoc(File appBundle) { - File provisionFile = getProvisionFileForBundle(appBundle) - if (provisionFile == null) { - return false - } - ProvisioningProfileReader reader = new ProvisioningProfileReader(provisionFile, this.commandRunner, this.plistHelper) - return reader.isAdHoc() - } - - def removeFrameworkFromExtensions(File bundle) { - // appex extensions should not contain extensions - if (FilenameUtils.getExtension(bundle.toString()).equalsIgnoreCase("appex")) { - File frameworksPath = new File(bundle, "Frameworks") - if (frameworksPath.exists()) { - FileUtils.deleteDirectory(frameworksPath) - } - } - - } - - def removeUnneededDylibsFromBundle(File bundle) { - File libswiftRemoteMirror = new File(bundle, "libswiftRemoteMirror.dylib") - if (libswiftRemoteMirror.exists()) { - libswiftRemoteMirror.delete() - } - } - - File getProvisionFileForBundle(File bundle) { - String bundleIdentifier = getIdentifierForBundle(bundle) - return ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) - } - - - def addSwiftSupport(File payloadPath, String applicationBundleName) { - File frameworksPath = new File(payloadPath, applicationBundleName + "/Frameworks") - if (!frameworksPath.exists()) { - return null - } - - File swiftLibArchive = new File(getArchiveDirectory(), "SwiftSupport") - - if (swiftLibArchive.exists()) { - copy(swiftLibArchive, payloadPath.getParentFile()) - return new File(payloadPath.getParentFile(), "SwiftSupport") - } - return null - } - - - private void createZipPackage(File packagePath, String extension, boolean includeSwiftSupport) { - File packageBundle = new File(outputPath, getIpaFileName() + "." + extension) - if (!packageBundle.parentFile.exists()) { - packageBundle.parentFile.mkdirs() - } - - List filesToZip = [] - filesToZip << packagePath - - if (includeSwiftSupport) { - File swiftSupportPath = addSwiftSupport(packagePath, applicationBundleName) - if (swiftSupportPath != null) { - filesToZip << swiftSupportPath - } - } - - File bcSymbolMapsPath = new File(packagePath.getParentFile(), "BCSymbolMaps") - if (bcSymbolMapsPath.exists()) { - filesToZip << bcSymbolMapsPath - } - - enumerateExtensionSupportDirectories(packagePath.getParentFile()) { File supportDirectory -> - filesToZip << supportDirectory - } - - createZip(packageBundle, packagePath.getParentFile(), packagePath, *filesToZip) - } - - private void enumerateExtensionSupportDirectories(File parentDirectory, Closure closure) { - def directoryNames = ["MessagesApplicationExtensionSupport"] - - for (String name in directoryNames) { - File supportDirectory = new File(parentDirectory, name) - if (supportDirectory.exists()) { - closure(supportDirectory) - } - } - } - - private void createIpa(File payloadPath, boolean addSwiftSupport) { - createZipPackage(payloadPath, "ipa", addSwiftSupport) - } - - private void createPackage(File packagePath) { - - createZipPackage(packagePath, "zip", false) - } - - - private String getIdentifierForBundle(File bundle) { - File infoPlist - - if (isDeviceBuildiOStvOS()) { - infoPlist = new File(bundle, "Info.plist"); - } else { - infoPlist = new File(bundle, "Contents/Info.plist") - } - - String bundleIdentifier = plistHelper.getValueFromPlist(infoPlist, "CFBundleIdentifier") - return bundleIdentifier - } - - - private void embedProvisioningProfileToBundle(File bundle) { - File mobileProvisionFile = getProvisionFileForBundle(bundle) - if (mobileProvisionFile != null) { - File embeddedProvisionFile - - String profileExtension = FilenameUtils.getExtension(mobileProvisionFile.absolutePath) - embeddedProvisionFile = new File(getAppContentPath(bundle) + "embedded." + profileExtension) - - logger.info("provision profile - {}", embeddedProvisionFile) - - FileUtils.copyFile(mobileProvisionFile, embeddedProvisionFile) - } - } - - private File createSigningDestination(String name) throws IOException { - File destination = new File(outputPath, name) - if (destination.exists()) { - FileUtils.deleteDirectory(destination) - } - destination.mkdirs(); - return destination; - } - - private File createApplicationFolder() throws IOException { - - if (isDeviceBuildiOStvOS()) { - return createSigningDestination("Payload") - } else { - // same folder as signing - if (!outputPath.exists()) { - outputPath.mkdirs() - } - return outputPath - } - } - - private File getInfoPlistFile() { - return new File(getAppContentPath() + "Info.plist") - } - - private String getAppContentPath() { - - return getAppContentPath(appBundles.last()) - } - - private String getAppContentPath(File bundle) { - if (project.xcodebuild.type == Type.iOS || project.xcodebuild.type == Type.tvOS) { - return bundle.absolutePath + "/" - } - return bundle.absolutePath + "/Contents/" - } - - def getIpaFileName() { - if (project.xcodebuild.ipaFileName) { - return project.xcodebuild.ipaFileName - } else { - return getApplicationNameFromArchive() - } - } - - - String getSigningIdentity() { - return codesignParameters.signingIdentity - } - void setSigningIdentity(String identity) { - codesignParameters.signingIdentity = identity + dependsOn(PackageLegacyTask.NAME) + dependsOn(PackageTaskIosAndTvOS.NAME) } } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 0d838fc5..42a7b52c 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -1,12 +1,15 @@ package org.openbakery.packaging import groovy.transform.CompileStatic +import org.gradle.api.Task +import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper +import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild import java.util.Optional @@ -16,7 +19,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader - public static final String TASK_NAME = "package" + public static final String NAME = "packageWithXcodeBuild" private static final String PLIST_KEY_METHOD = "method" private static final String PLIST_KEY_COMPILE_BITCODE = "compileBitcode" @@ -31,6 +34,14 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) + + onlyIf(new Spec() { + @Override + boolean isSatisfiedBy(Task task) { + return getXcodeExtension().getType() == Type.iOS || + getXcodeExtension().getType() == Type.tvOS + } + }) } @Input diff --git a/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy index ca219b68..8675fc04 100644 --- a/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy @@ -3,6 +3,7 @@ package org.openbakery import org.apache.tools.ant.util.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.openbakery.packaging.PackageTask import spock.lang.Specification class AbstractDistributeTaskSpecification extends Specification { @@ -23,7 +24,7 @@ class AbstractDistributeTaskSpecification extends Specification { project.apply plugin: org.openbakery.XcodePlugin - distributeTask = project.tasks.findByName(XcodePlugin.PACKAGE_TASK_NAME); + distributeTask = project.tasks.findByName(PackageTask.NAME); //XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "ExampleWatchkit.xcodeproj/project.pbxproj")); diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index c4cbb4c2..2047bba4 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -23,7 +23,7 @@ class PackageTaskSpecification extends Specification { Project project - PackageTask packageTask + PackageLegacyTask packageTask ApplicationDummy applicationDummy CommandRunner commandRunner = Mock(CommandRunner) @@ -55,7 +55,7 @@ class PackageTaskSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(XcodePlugin.PACKAGE_TASK_NAME) + packageTask = project.getTasks().getByPath(PackageTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy index b0d7b92f..3ff611cf 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy @@ -5,7 +5,6 @@ import org.apache.commons.io.FilenameUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake import org.openbakery.util.PathHelper @@ -18,7 +17,7 @@ import java.util.zip.ZipFile class PackageTask_OSXSpecification extends Specification { Project project - PackageTask packageTask; + PackageLegacyTask packageTask; CommandRunner commandRunner = Mock(CommandRunner) @@ -57,7 +56,7 @@ class PackageTask_OSXSpecification extends Specification { project.xcodebuild.signing.keychain = keychain.absolutePath project.xcodebuild.signing.identity = 'iPhone Developer: Firstname Surename (AAAAAAAAAA)' - packageTask = project.getTasks().getByPath(XcodePlugin.PACKAGE_TASK_NAME) + packageTask = project.getTasks().getByPath(PackageTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy index 1427baab..b8f4ba17 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy @@ -4,7 +4,6 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake import org.openbakery.util.PathHelper @@ -15,7 +14,7 @@ class PackageTask_WatchAppSpecification extends Specification { Project project - PackageTask packageTask; + PackageLegacyTask packageTask; CommandRunner commandRunner = Mock(CommandRunner) @@ -49,7 +48,7 @@ class PackageTask_WatchAppSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(XcodePlugin.PACKAGE_TASK_NAME) + packageTask = project.getTasks().getByPath(PackageTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy index dc4f6219..1053d522 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy @@ -4,7 +4,6 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake import org.openbakery.util.PathHelper @@ -15,7 +14,7 @@ class PackageTask_WatchKitSpecification extends Specification { Project project - PackageTask packageTask; + PackageLegacyTask packageTask; CommandRunner commandRunner = Mock(CommandRunner) @@ -45,7 +44,7 @@ class PackageTask_WatchKitSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(XcodePlugin.PACKAGE_TASK_NAME) + packageTask = project.getTasks().getByPath(PackageTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy index 04be076b..6d0fd85e 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy @@ -1,31 +1,28 @@ package org.openbakery.signing -import ch.qos.logback.core.util.FileUtil import org.apache.commons.configuration.plist.XMLPropertyListConfiguration import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.configuration.Configuration import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.configuration.ConfigurationFromPlist -import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin +import org.openbakery.packaging.PackageLegacyTask import org.openbakery.packaging.PackageTask import org.openbakery.util.PlistHelper +import org.openbakery.xcode.Type import spock.lang.Specification import static org.hamcrest.MatcherAssert.assertThat import static org.hamcrest.Matchers.equalTo import static org.hamcrest.Matchers.is - class ProvisioningProfileReaderSpecification extends Specification { Project project - PackageTask packageTask; + PackageLegacyTask packageTask; File projectDir File buildOutputDirectory @@ -44,7 +41,7 @@ class ProvisioningProfileReaderSpecification extends Specification { project.xcodebuild.type = Type.macOS project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(XcodePlugin.PACKAGE_TASK_NAME) + packageTask = project.getTasks().getByPath(PackageTask.NAME) buildOutputDirectory = new File(project.xcodebuild.symRoot, project.xcodebuild.configuration) From 5d691f0fb50efce9a4484f242e0a1429f0fb1073 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 15:28:49 +0100 Subject: [PATCH 066/121] Fix the unit test --- .../org/openbakery/AbstractDistributeTaskSpecification.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy index 8675fc04..5ecbbefc 100644 --- a/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/AbstractDistributeTaskSpecification.groovy @@ -3,7 +3,7 @@ package org.openbakery import org.apache.tools.ant.util.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder -import org.openbakery.packaging.PackageTask +import org.openbakery.packaging.PackageLegacyTask import spock.lang.Specification class AbstractDistributeTaskSpecification extends Specification { @@ -24,7 +24,7 @@ class AbstractDistributeTaskSpecification extends Specification { project.apply plugin: org.openbakery.XcodePlugin - distributeTask = project.tasks.findByName(PackageTask.NAME); + distributeTask = project.tasks.findByName(PackageLegacyTask.NAME) //XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "ExampleWatchkit.xcodeproj/project.pbxproj")); From 674ce3f262bf4b6b5d7a9822e98eda9e87d50115 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 15:50:41 +0100 Subject: [PATCH 067/121] Fix more unit tests --- .../openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy | 2 +- .../org/openbakery/XcodeBuildArchiveTaskSpecification.groovy | 2 +- .../groovy/org/openbakery/XcodePluginSpecification.groovy | 4 +++- .../org/openbakery/packaging/PackageTaskSpecification.groovy | 2 +- .../openbakery/packaging/PackageTask_OSXSpecification.groovy | 2 +- .../packaging/PackageTask_WatchAppSpecification.groovy | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy index e6ea52ca..7c280e23 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy @@ -32,7 +32,7 @@ class XcodeBuildArchiveTaskOSXSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" project.xcodebuild.signing.identity = "my identity" - xcodeBuildArchiveTask = project.getTasks().getByPath(XcodePlugin.ARCHIVE_TASK_NAME) + xcodeBuildArchiveTask = project.getTasks().getByPath(XcodeBuildLegacyArchiveTask.NAME) xcodeBuildArchiveTask.commandRunner = commandRunner xcodeBuildArchiveTask.parameters.type = Type.macOS diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy index 18d800b3..0c94a8f3 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy @@ -48,7 +48,7 @@ class XcodeBuildArchiveTaskSpecification extends Specification { project.xcodebuild.signing.identity = "my identity" - xcodeBuildArchiveTask = project.getTasks().getByPath(XcodePlugin.ARCHIVE_TASK_NAME) + xcodeBuildArchiveTask = project.getTasks().getByPath(XcodeBuildLegacyArchiveTask.NAME) xcodeBuildArchiveTask.plistHelper = plistHelper xcodeBuildArchiveTask.commandRunner = commandRunner xcodeBuildArchiveTask.xcode.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy index d6c19d86..57b75571 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy @@ -46,7 +46,9 @@ class XcodePluginSpecification extends Specification { def "contain task archive"() { expect: - project.tasks.findByName('archive') instanceof XcodeBuildLegacyArchiveTask + project.tasks.findByName(XcodeBuildArchiveTask.NAME) instanceof XcodeBuildArchiveTask + project.tasks.findByName(XcodeBuildLegacyArchiveTask.NAME) instanceof XcodeBuildLegacyArchiveTask + project.tasks.findByName(XcodeBuildArchiveTaskIosAndTvOS.NAME) instanceof XcodeBuildArchiveTaskIosAndTvOS } diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 2047bba4..0349dc8c 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -55,7 +55,7 @@ class PackageTaskSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(PackageTask.NAME) + packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy index 3ff611cf..64d6fcb1 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_OSXSpecification.groovy @@ -56,7 +56,7 @@ class PackageTask_OSXSpecification extends Specification { project.xcodebuild.signing.keychain = keychain.absolutePath project.xcodebuild.signing.identity = 'iPhone Developer: Firstname Surename (AAAAAAAAAA)' - packageTask = project.getTasks().getByPath(PackageTask.NAME) + packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy index b8f4ba17..cc596e21 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchAppSpecification.groovy @@ -48,7 +48,7 @@ class PackageTask_WatchAppSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(PackageTask.NAME) + packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner From 920f4fe4b25d119f3f25b9089ce1ac1473652865 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 15:54:41 +0100 Subject: [PATCH 068/121] Fix the unit tests --- .../packaging/PackageTask_WatchKitSpecification.groovy | 2 +- .../signing/ProvisioningProfileReaderSpecification.groovy | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy index 1053d522..3f56177a 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTask_WatchKitSpecification.groovy @@ -44,7 +44,7 @@ class PackageTask_WatchKitSpecification extends Specification { project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(PackageTask.NAME) + packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) packageTask.plistHelper = plistHelperStub packageTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy index 6d0fd85e..13db20a7 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy @@ -9,7 +9,6 @@ import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.configuration.ConfigurationFromPlist import org.openbakery.packaging.PackageLegacyTask -import org.openbakery.packaging.PackageTask import org.openbakery.util.PlistHelper import org.openbakery.xcode.Type import spock.lang.Specification @@ -41,7 +40,7 @@ class ProvisioningProfileReaderSpecification extends Specification { project.xcodebuild.type = Type.macOS project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" - packageTask = project.getTasks().getByPath(PackageTask.NAME) + packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) buildOutputDirectory = new File(project.xcodebuild.symRoot, project.xcodebuild.configuration) From 3aef8683a045a2e960b94040a6b3eec746c413b7 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 16:04:14 +0100 Subject: [PATCH 069/121] Move the archive tasks to a dedicated package --- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 3 +++ .../openbakery/{ => archiving}/XcodeBuildArchiveTask.groovy | 4 +++- .../{ => archiving}/XcodeBuildArchiveTaskIosAndTvOS.groovy | 5 ++++- .../{ => archiving}/XcodeBuildLegacyArchiveTask.groovy | 6 +++++- .../openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy | 1 + .../openbakery/XcodeBuildArchiveTaskSpecification.groovy | 1 + .../groovy/org/openbakery/XcodePluginSpecification.groovy | 3 +++ 7 files changed, 20 insertions(+), 3 deletions(-) rename plugin/src/main/groovy/org/openbakery/{ => archiving}/XcodeBuildArchiveTask.groovy (78%) rename plugin/src/main/groovy/org/openbakery/{ => archiving}/XcodeBuildArchiveTaskIosAndTvOS.groovy (90%) rename plugin/src/main/groovy/org/openbakery/{ => archiving}/XcodeBuildLegacyArchiveTask.groovy (98%) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index dbf5580f..007db494 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -27,6 +27,9 @@ import org.openbakery.appledoc.AppledocTask import org.openbakery.appstore.AppstorePluginExtension import org.openbakery.appstore.AppstoreUploadTask import org.openbakery.appstore.AppstoreValidateTask +import org.openbakery.archiving.XcodeBuildArchiveTask +import org.openbakery.archiving.XcodeBuildArchiveTaskIosAndTvOS +import org.openbakery.archiving.XcodeBuildLegacyArchiveTask import org.openbakery.carthage.CarthageCleanTask import org.openbakery.carthage.CarthageUpdateTask import org.openbakery.cocoapods.CocoapodsBootstrapTask diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTask.groovy similarity index 78% rename from plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy rename to plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTask.groovy index 97d0cb8a..55067054 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTask.groovy @@ -1,4 +1,6 @@ -package org.openbakery +package org.openbakery.archiving + +import org.openbakery.AbstractXcodeBuildTask class XcodeBuildArchiveTask extends AbstractXcodeBuildTask { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy similarity index 90% rename from plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy rename to plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index b7ac1087..7166ea24 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,9 +1,12 @@ -package org.openbakery +package org.openbakery.archiving import groovy.transform.CompileStatic import org.gradle.api.Task import org.gradle.api.specs.Spec import org.gradle.api.tasks.* +import org.openbakery.AbstractXcodeBuildTask +import org.openbakery.PrepareXcodeArchivingTask +import org.openbakery.XcodePlugin import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy similarity index 98% rename from plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy rename to plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy index ee1c0be1..668a7f77 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildLegacyArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy @@ -13,13 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.openbakery +package org.openbakery.archiving import groovy.io.FileType import org.apache.commons.io.FileUtils import org.gradle.api.Task import org.gradle.api.specs.Spec import org.gradle.api.tasks.TaskAction +import org.openbakery.AbstractXcodeBuildTask +import org.openbakery.BuildConfiguration +import org.openbakery.CommandRunnerException +import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.util.PathHelper import org.openbakery.xcode.Type diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy index 7c280e23..4fd8d4b2 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskOSXSpecification.groovy @@ -4,6 +4,7 @@ import org.apache.commons.configuration.plist.XMLPropertyListConfiguration import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.openbakery.archiving.XcodeBuildLegacyArchiveTask import org.openbakery.testdouble.PlistHelperStub import org.openbakery.xcode.Type import spock.lang.Specification diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy index 0c94a8f3..67937bce 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy @@ -5,6 +5,7 @@ import org.apache.commons.io.FileUtils import org.apache.commons.lang.RandomStringUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.openbakery.archiving.XcodeBuildLegacyArchiveTask import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.SimulatorControlStub import org.openbakery.testdouble.XcodeFake diff --git a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy index 57b75571..c6eb4529 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodePluginSpecification.groovy @@ -9,6 +9,9 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.appstore.AppstorePluginExtension import org.openbakery.appstore.AppstoreUploadTask import org.openbakery.appstore.AppstoreValidateTask +import org.openbakery.archiving.XcodeBuildArchiveTask +import org.openbakery.archiving.XcodeBuildArchiveTaskIosAndTvOS +import org.openbakery.archiving.XcodeBuildLegacyArchiveTask import org.openbakery.carthage.CarthageCleanTask import org.openbakery.carthage.CarthageUpdateTask import org.openbakery.cocoapods.CocoapodsBootstrapTask From eb7e01f5d5af7bdf17b6412d7e4ac3b813589530 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 1 May 2018 16:20:12 +0100 Subject: [PATCH 070/121] Adjustements --- .../main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy | 3 ++- .../org/openbakery/{packaging => }/ReleaseNotesTask.groovy | 2 +- .../groovy/org/openbakery/XcodeBuildPluginExtension.groovy | 2 +- plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy | 1 - .../groovy/org/openbakery/packaging/ReleaseNotesTest.groovy | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename plugin/src/main/groovy/org/openbakery/{packaging => }/ReleaseNotesTask.groovy (98%) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 1e090a46..39d77274 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -99,7 +99,8 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { } XcodeBuildPluginExtension getXcodeExtension() { - return project.getExtensions().getByType(XcodeBuildPluginExtension.class) + return project.getExtensions() + .getByType(XcodeBuildPluginExtension.class) } String getBundleIdentifier() { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy b/plugin/src/main/groovy/org/openbakery/ReleaseNotesTask.groovy similarity index 98% rename from plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy rename to plugin/src/main/groovy/org/openbakery/ReleaseNotesTask.groovy index 96a8202f..7acb2854 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/ReleaseNotesTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/ReleaseNotesTask.groovy @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.openbakery.packaging +package org.openbakery import org.apache.commons.io.FileUtils import org.gradle.api.DefaultTask diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index ce510fed..8d25b748 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -71,7 +71,7 @@ class XcodeBuildPluginExtension { boolean simulator = true Type type = Type.iOS - String target = null + String target Object dstRoot Object objRoot Object symRoot diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 007db494..6ed87144 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -54,7 +54,6 @@ import org.openbakery.oclint.OCLintTask import org.openbakery.packaging.PackageLegacyTask import org.openbakery.packaging.PackageTask import org.openbakery.packaging.PackageTaskIosAndTvOS -import org.openbakery.packaging.ReleaseNotesTask import org.openbakery.signing.* import org.openbakery.simulators.* import org.slf4j.Logger diff --git a/plugin/src/test/groovy/org/openbakery/packaging/ReleaseNotesTest.groovy b/plugin/src/test/groovy/org/openbakery/packaging/ReleaseNotesTest.groovy index c5cdd4ef..baba8159 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/ReleaseNotesTest.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/ReleaseNotesTest.groovy @@ -4,7 +4,7 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.XcodePlugin -import org.openbakery.packaging.ReleaseNotesTask +import org.openbakery.ReleaseNotesTask import org.junit.Before import org.junit.After import org.junit.Test From 96debe348ce22156e485134a934140533b737d8f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 2 May 2018 15:44:14 +0100 Subject: [PATCH 071/121] Adjustement in the rules around the bitcode setting --- .../packaging/PackageTaskIosAndTvOS.groovy | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 42a7b52c..1d490e6b 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -22,6 +22,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { public static final String NAME = "packageWithXcodeBuild" private static final String PLIST_KEY_METHOD = "method" + private static final String PLIST_KEY_SIGNING_STYLE = "signingStyle" private static final String PLIST_KEY_COMPILE_BITCODE = "compileBitcode" private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" private static final String PLIST_KEY_SIGNING_CERTIFICATE = "signingCertificate" @@ -44,6 +45,23 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { }) } + @Input + boolean getBitCode() { + boolean result = getXcodeExtension().bitcode + SigningMethod method = getMethod() + + if (method == SigningMethod.AppStore + && getXcodeExtension().type == Type.tvOS) { + assert result: "Invalid configuration for the TvOS target " + + "`AppStore` upload requires BitCode enabled." + } else if (method != SigningMethod.AppStore) { + assert !result: "The BitCode setting (`xcodebuild.bitcode`) should be enabled only " + + "for the `AppStore` signing method" + } + + return result + } + @Input String getBundleIdentifier() { return super.getBundleIdentifier() @@ -114,7 +132,11 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { // BitCode should be compiled only for AppStore builds plistHelper.addValueForPlist(file, PLIST_KEY_COMPILE_BITCODE, - getMethod() == SigningMethod.AppStore) + getBitCode()) + + plistHelper.addValueForPlist(file, + PLIST_KEY_SIGNING_STYLE, + "manual") } private void packageIt() { From c27778de8e155f8568a203ba06f2015d6f744f72 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 3 May 2018 09:47:58 +0100 Subject: [PATCH 072/121] Remove duplication by adding a helper method --- .../packaging/PackageTaskIosAndTvOS.groovy | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 1d490e6b..735c8fd3 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -26,6 +26,8 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private static final String PLIST_KEY_COMPILE_BITCODE = "compileBitcode" private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" private static final String PLIST_KEY_SIGNING_CERTIFICATE = "signingCertificate" + private static final String PLIST_VALUE_SIGNING_METHOD_MANUAL = "manual" + PackageTaskIosAndTvOS() { super() @@ -113,30 +115,40 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { File file = getExportOptionsPlistFile() plistHelper.create(file) - plistHelper.addValueForPlist(file, - PLIST_KEY_METHOD, + + // Signing method + addStringValueForPlist(PLIST_KEY_METHOD, getMethod().value) - // provisioning profiles + // Provisioning profiles map list HashMap map = new HashMap<>() map.put(reader.getApplicationIdentifier(), reader.getName()) plistHelper.addDictForPlist(file, PLIST_KEY_PROVISIONING_PROFILE, map) - // certificate - plistHelper.addValueForPlist(file, - PLIST_KEY_SIGNING_CERTIFICATE, + // Certificate name + addStringValueForPlist(PLIST_KEY_SIGNING_CERTIFICATE, getSignatureFriendlyName()) - // BitCode should be compiled only for AppStore builds + // BitCode plistHelper.addValueForPlist(file, PLIST_KEY_COMPILE_BITCODE, getBitCode()) - plistHelper.addValueForPlist(file, - PLIST_KEY_SIGNING_STYLE, - "manual") + // SigningMethod + addStringValueForPlist(PLIST_KEY_SIGNING_STYLE, + PLIST_VALUE_SIGNING_METHOD_MANUAL) + } + + private void addStringValueForPlist(String key, + String value) { + assert key != null + assert value != null + + plistHelper.addValueForPlist(getExportOptionsPlistFile(), + key, + value) } private void packageIt() { From 325308f814b0b967987a1b0368601c1276e4f322 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 4 May 2018 15:45:00 +0100 Subject: [PATCH 073/121] Add functional unit test to the PrepareXcodeArchiving task --- build.gradle | 21 ++ .../org/openbakery/util/PathHelper.groovy | 5 +- plugin/build.gradle | 23 ++ ...PrepareXcodeArchivingFunctionalTest.groovy | 188 ++++++++++ .../TestProject.xcodeproj/project.pbxproj | 337 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../TestProject/TestProject/AppDelegate.swift | 46 +++ .../AppIcon.appiconset/Contents.json | 98 +++++ .../TestProject/Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../TestProject/Base.lproj/Main.storyboard | 24 ++ .../TestProject/TestProject/Info.plist | 45 +++ .../TestProject/ViewController.swift | 25 ++ .../resources/fake_distribution.p12 | Bin 0 -> 2709 bytes .../resources/test1.mobileprovision | 46 +++ .../openbakery/AbstractXcodeBuildTask.groovy | 61 +++- .../PrepareXcodeArchivingTask.groovy | 6 +- .../packaging/PackageTaskIosAndTvOS.groovy | 41 ++- .../project.pbxproj | 325 +++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../functionaltestproject/AppDelegate.swift | 46 +++ .../AppIcon.appiconset/Contents.json | 93 +++++ .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../Base.lproj/Main.storyboard | 24 ++ .../functionaltestproject/Info.plist | 45 +++ .../ViewController.swift | 25 ++ .../openbakery-wildcard.mobileprovision | 42 +++ .../PackageTaskIosAndTvOSTest.groovy | 48 +++ 30 files changed, 1672 insertions(+), 28 deletions(-) create mode 100644 plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.pbxproj create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/AppDelegate.swift create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/Contents.json create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/Main.storyboard create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/Info.plist create mode 100644 plugin/src/functionalTest/resources/TestProject/TestProject/ViewController.swift create mode 100644 plugin/src/functionalTest/resources/fake_distribution.p12 create mode 100644 plugin/src/functionalTest/resources/test1.mobileprovision create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist create mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift create mode 100644 plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision create mode 100644 plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy diff --git a/build.gradle b/build.gradle index afccbb92..e28f48db 100644 --- a/build.gradle +++ b/build.gradle @@ -55,6 +55,27 @@ allprojects { substitute module('ch.qos.logback:logback-classic') with module('org.slf4j:slf4j-api:1.7.+') } } + + // Write the plugin's classpath to a file to share with the tests + task createClasspathManifest { + def outputDir = file("$buildDir/$name") + + inputs.files sourceSets.main.runtimeClasspath + outputs.dir outputDir + + doLast { + outputDir.mkdirs() + file("$outputDir/plugin-classpath.txt").text = project.files(project.rootProject.subprojects + .collect { it.sourceSets.main.runtimeClasspath } + .toList()) + .files + .join("\n") + } + } + + dependencies { + testRuntime files(createClasspathManifest) + } } diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index c7ae4be7..c6fffffc 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -12,9 +12,8 @@ class PathHelper { public static final String IPHONE_OS = "iphoneos" public static final String FOLDER_ARCHIVE = "archive" public static final String FOLDER_PACKAGE = "package" - - private static final String ARCHIVE_FILE_NAME = "archive.xcconfig" - private static final String EXTENSION_XC_ARCHIVE = ".xcarchive" + public static final String ARCHIVE_FILE_NAME = "archive.xcconfig" + public static final String EXTENSION_XC_ARCHIVE = ".xcarchive" static File resolvePath(Type type, boolean simulator, diff --git a/plugin/build.gradle b/plugin/build.gradle index fc1ff613..8c6245f5 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -59,6 +59,29 @@ task sourcesJar(type: Jar) { classifier = 'sources' } +sourceSets { + functionalTest { + groovy { + srcDir file('src/functionalTest/groovy') + } + resources { + srcDir file('src/functionalTest/resources') + } + compileClasspath += sourceSets.main.output + configurations.testRuntime + runtimeClasspath += output + compileClasspath + } +} + +task functionalTest(type: Test) { + testClassesDirs = sourceSets.functionalTest.output.classesDirs + classpath = sourceSets.functionalTest.runtimeClasspath +} + +check.dependsOn functionalTest + +gradlePlugin { + testSourceSets sourceSets.functionalTest +} uploadArchives { repositories { diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy new file mode 100644 index 00000000..26b4ea2e --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -0,0 +1,188 @@ +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 spock.lang.Unroll + +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) + } + + @Unroll("It should fail to resolve provisioning for bundleIdentifier : #bundleIdentifier") + def "Should try to resolve provisioning for the bundle identifier"() { + setup: + setupBuildFile() + + when: + if (bundleIdentifier != null) { + buildFile << """ + xcodebuild { + infoplist { + bundleIdentifier = "$bundleIdentifier" + } + } + """ + } + + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(PrepareXcodeArchivingTask.NAME) + .withPluginClasspath(pluginClasspath) + .buildAndFail() + + then: + result.output.contains("> Cannot resolve a valid provisioning profile for bundle identifier : " + + exceptionValue) + + where: + bundleIdentifier | exceptionValue + null | "\$(PRODUCT_BUNDLE_IDENTIFIER)" + "invalid.bundle.identifier" | "invalid.bundle.identifier" + } + + def "The task should fail due to invalid configuration"() { + setup: + setupBuildFile() + + when: + buildFile << """ + xcodebuild { + infoplist { + bundleIdentifier = "org.openbakery.test.ExampleWidget" + } + } + """ + + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(PrepareXcodeArchivingTask.NAME) + .withPluginClasspath(pluginClasspath) + .buildAndFail() + + then: + result.output.contains("The signing certificate password is not defined") + } + + 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 file should be properly generated and populated from configured values" + + File outputFile = new File(testProjectDir.root, "build/" + + PathHelper.FOLDER_ARCHIVE + + "/" + PathHelper.ARCHIVE_FILE_NAME) + + 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") + } + + 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/resources/TestProject/TestProject.xcodeproj/project.pbxproj b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.pbxproj new file mode 100644 index 00000000..ea040bd5 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.pbxproj @@ -0,0 +1,337 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + BFD99BC5209C6A8800AF800E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD99BC4209C6A8800AF800E /* AppDelegate.swift */; }; + BFD99BC7209C6A8800AF800E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD99BC6209C6A8800AF800E /* ViewController.swift */; }; + BFD99BCA209C6A8800AF800E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFD99BC8209C6A8800AF800E /* Main.storyboard */; }; + BFD99BCC209C6A8A00AF800E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BFD99BCB209C6A8A00AF800E /* Assets.xcassets */; }; + BFD99BCF209C6A8A00AF800E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFD99BCD209C6A8A00AF800E /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + BFD99BC1209C6A8800AF800E /* TestProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BFD99BC4209C6A8800AF800E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + BFD99BC6209C6A8800AF800E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + BFD99BC9209C6A8800AF800E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + BFD99BCB209C6A8A00AF800E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + BFD99BCE209C6A8A00AF800E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + BFD99BD0209C6A8A00AF800E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BFD99BBE209C6A8800AF800E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BFD99BB8209C6A8700AF800E = { + isa = PBXGroup; + children = ( + BFD99BC3209C6A8800AF800E /* TestProject */, + BFD99BC2209C6A8800AF800E /* Products */, + ); + sourceTree = ""; + }; + BFD99BC2209C6A8800AF800E /* Products */ = { + isa = PBXGroup; + children = ( + BFD99BC1209C6A8800AF800E /* TestProject.app */, + ); + name = Products; + sourceTree = ""; + }; + BFD99BC3209C6A8800AF800E /* TestProject */ = { + isa = PBXGroup; + children = ( + BFD99BC4209C6A8800AF800E /* AppDelegate.swift */, + BFD99BC6209C6A8800AF800E /* ViewController.swift */, + BFD99BC8209C6A8800AF800E /* Main.storyboard */, + BFD99BCB209C6A8A00AF800E /* Assets.xcassets */, + BFD99BCD209C6A8A00AF800E /* LaunchScreen.storyboard */, + BFD99BD0209C6A8A00AF800E /* Info.plist */, + ); + path = TestProject; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BFD99BC0209C6A8800AF800E /* TestProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = BFD99BD3209C6A8A00AF800E /* Build configuration list for PBXNativeTarget "TestProject" */; + buildPhases = ( + BFD99BBD209C6A8800AF800E /* Sources */, + BFD99BBE209C6A8800AF800E /* Frameworks */, + BFD99BBF209C6A8800AF800E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TestProject; + productName = TestProject; + productReference = BFD99BC1209C6A8800AF800E /* TestProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFD99BB9209C6A8700AF800E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0930; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = Massive; + TargetAttributes = { + BFD99BC0209C6A8800AF800E = { + CreatedOnToolsVersion = 9.3; + }; + }; + }; + buildConfigurationList = BFD99BBC209C6A8700AF800E /* Build configuration list for PBXProject "TestProject" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BFD99BB8209C6A8700AF800E; + productRefGroup = BFD99BC2209C6A8800AF800E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BFD99BC0209C6A8800AF800E /* TestProject */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BFD99BBF209C6A8800AF800E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BFD99BCF209C6A8A00AF800E /* LaunchScreen.storyboard in Resources */, + BFD99BCC209C6A8A00AF800E /* Assets.xcassets in Resources */, + BFD99BCA209C6A8800AF800E /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BFD99BBD209C6A8800AF800E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BFD99BC7209C6A8800AF800E /* ViewController.swift in Sources */, + BFD99BC5209C6A8800AF800E /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + BFD99BC8209C6A8800AF800E /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BFD99BC9209C6A8800AF800E /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + BFD99BCD209C6A8A00AF800E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BFD99BCE209C6A8A00AF800E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + BFD99BD1209C6A8A00AF800E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + BFD99BD2209C6A8A00AF800E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BFD99BD4209C6A8A00AF800E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = TestProject/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.TestProject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BFD99BD5209C6A8A00AF800E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = TestProject/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.TestProject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BFD99BBC209C6A8700AF800E /* Build configuration list for PBXProject "TestProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BFD99BD1209C6A8A00AF800E /* Debug */, + BFD99BD2209C6A8A00AF800E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BFD99BD3209C6A8A00AF800E /* Build configuration list for PBXNativeTarget "TestProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BFD99BD4209C6A8A00AF800E /* Debug */, + BFD99BD5209C6A8A00AF800E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFD99BB9209C6A8700AF800E /* Project object */; +} diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..2bf8bd93 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/AppDelegate.swift b/plugin/src/functionalTest/resources/TestProject/TestProject/AppDelegate.swift new file mode 100644 index 00000000..0e25d993 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// TestProject +// +// Created by Johann Martinache on 04/05/2018. +// Copyright © 2018 Massive. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d8db8d65 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/Contents.json b/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard b/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f83f6fd5 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/Main.storyboard b/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/Main.storyboard new file mode 100644 index 00000000..03c13c22 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/Info.plist b/plugin/src/functionalTest/resources/TestProject/TestProject/Info.plist new file mode 100644 index 00000000..16be3b68 --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/plugin/src/functionalTest/resources/TestProject/TestProject/ViewController.swift b/plugin/src/functionalTest/resources/TestProject/TestProject/ViewController.swift new file mode 100644 index 00000000..65114f2e --- /dev/null +++ b/plugin/src/functionalTest/resources/TestProject/TestProject/ViewController.swift @@ -0,0 +1,25 @@ +// +// ViewController.swift +// TestProject +// +// Created by Johann Martinache on 04/05/2018. +// Copyright © 2018 Massive. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + +} + diff --git a/plugin/src/functionalTest/resources/fake_distribution.p12 b/plugin/src/functionalTest/resources/fake_distribution.p12 new file mode 100644 index 0000000000000000000000000000000000000000..208b05e0ad22ba0057fe49cd81023911d46dbbce GIT binary patch literal 2709 zcmY+Ec|6n$7sh`xhGE8@ec!WY?6Qj}Axj8D*|&yaEJ>F8qmsOY(UiR!V{9p1*-Iiz z$SzmRwPjS6#+vm`_w&B*ecwOM=bZCA&pCg7Q6M4<3SmHj2p1+6#oOm@@32AOkP;Aa z4hAC3>9Pq5geCrCF_nNYEM2+=g#h&C_m2ZXi7+Al{ecz2gkpy=M=r$duDhFQL7~h* z5(v|6Rf9NmomM7t*V-XTF^0Pj&h5K->|>t5+h3x$Sdx1O3`b}@yuu~u`FU}-_PRp$;$Tp zL1sSco|BZoclB{yP?SSL%posa;bKs^CvWD!WY@IuDQW6xk=E-D+LCLVXywbQqx#y? zd5Yq+>(Z#wa=7k?v7)CrqUQ;nUE=NSUT5tPI=P?q_r46Dk>uRkbaEz&^jk!|N6wWU zw-$7GfAR4bY0Kwwp0dKnUQd_7os5?G$avuD#`jG@FlihN?#);_tx4Tzp*Y+MXhLuz z3P0NNl+uXo28NGs=Oz|c`^;GKI3>lVPgXE+C28zn%xXQ-6P)sP7llqepf$F_$agup`{qy$w!_d>SB${3JN`MMPaR{N zqkLVQ=WgVPM5#-+inK7KG;&ssk*>CUDhMhS7*8fQGF=d@=XMbIX0+rxko*Lk%^FU& zU)-u|#zmi4-u8q(U}0u1r0txPR$O5_dU~ofm0B$jXn{w|SzI5uc=o`_idE$E>cZ|E zd24O2c?oV44jG)qOA82>si!eOj~@YsdfVHVH;E%LT3cz?X1;-hVqKd=p*yMjtJQIY zVFBIuT7&VU=X~l}H$m#qOz__RDssjwUxXPYw2dcWee{w*nN8HUs za@Yd*^a4GQ?!)AAzc!095rWPx*Xrq*T~yR@;nIAr$Y#$`^kVO-;#k%Y(`U}GH(T8g zl&5Ntg>mijU(+;iW9rsfW|ah0U=+>hLd%B1I$QFKtO)WwD0xw&KKO8K9l%U|3P=o7sr~anFN^~^f$ODXc^LLJtg31(4Rtc)2;R_FZ2ECH|YEvpJ?K# z(T%X)JiR3dm0kHgZPKj7o)c@>T)q6=;tl&_r|MwnkGndLl*Js#3E6vG*rQRlM5TB~{B)irsx=%}WpwEV~qhcbYy7(=h8h+yr-;Xr*&?*xT4)uZG|*lbcmtDL}i8Yl3EKxVE^D zV?H7O{gKhq4gEYaX<80hMB00<2Z@;1;uIU+%t9jPeeowtm5=-dt!ol|wbwr)hNgmF z51&a@;EVL2jo-@Tun>=t0jnzmEW=THW6oihC2|9q9SmcKT4Zvz)Y>!Vzf!w-7(KgT z1QSt>6H*HT&r-6EPyTj@Ci_~-Y~rKUhoFkJ7$HgWUPPJbn15K>m;x1ka|-+T;dg-H zlt^SCCoDB0`=ZkOm4YX8;k5W^PQn%A5#@`yp_`WF%VzUBYaMyHsdcRrqdEwabD1(6 z(vzkmy!^!h-mzO#?S`I;eM^1m{SCudF+I2CPb%^#M%9O%-YshJ?*`-cm+W0`nM~RB zW({;ZJs+=l+0;!+_8J{OTIhV5-&RR!1?#Le&tzT}*YL^M_Nqci zU#mMef+%lT$kIWR8(54E@7ufm{Yo~XUZt}oK9*ymn{ah#jV$wOk- z7pU07pFlx#k8S2d29$P$Oi*idq&(QUYez;C>@p|IKJp-(_P@{V2GO&?oiwDiox^z9@lG zi`H_OYCMr4HR)k>eb1dO^c#eqk(y^9aHKE4Qe^<6k9AUy66sWp(^*J9lu8 zNX~7|!Gx6j!P_HBaZ%V`xHA<~%8X1Axy1X78pSdc8q(y9?@aFs6IKBur^zI_V;dIkU{dK#3?&m>peNbr2M3c$JA83Vo0wl>HgA z7*x3yo@~dvU~OGmUg$hSBBrmW8g_uV7ba^&^nQNqgiurGM=qg1qbZ5^7R8!jJrNWIyLBa#`}y7Fbs z&+u|e+-8&a!Whl@SBGUgC@LntCqA;mmv6Mov8MB`zf7ym$1%4tcKEXthq~a3zN}YvB|&w2cl-W_6vUhAjaqFe?~7`^+i|ZrRNr~3 zH=*;CHhYmjh@m=GmPYIx%)U73A1qA6_6aglq+JR9u}{AK95wdMl)F)`5kZ|B_dUaz zM9vrG{fRR$DE{{1L^66G9rA%&#f-_+18$(X#(I@ck_s4nb4HMr1GpG(RoTbj!sHnx z_o~%hiPAB`*BuAgEUlj{#i;#OfRg?%9$9$R_+UIoIf7Mv6K|_P0<>L=@M=IuHDlPw literal 0 HcmV?d00001 diff --git a/plugin/src/functionalTest/resources/test1.mobileprovision b/plugin/src/functionalTest/resources/test1.mobileprovision new file mode 100644 index 00000000..d8fded0c --- /dev/null +++ b/plugin/src/functionalTest/resources/test1.mobileprovision @@ -0,0 +1,46 @@ +// a Dummy Mobile Provistioning File to test the ProvisioningProfileIDReader + + + + ApplicationIdentifierPrefix + + AAAAAAAAAAA + + CreationDate + 2011-06-16T08:57:51Z + DeveloperCertificates + + + + + Entitlements + + application-identifier + AAAAAAAAAAA.org.openbakery.test.ExampleWidget + get-task-allow + + keychain-access-groups + + AAAAAAAAAAA.* + + + ExpirationDate + 2079-07-04T08:57:51Z + Name + ad hoc + ProvisionedDevices + + 1234 + + TimeToLive + 24855 + UUID + XXXXFFFF-AAAA-BBBB-CCCC-DDDDEEEEFFFF + Version + 1 + TeamIdentifier + + XXXYYYZZZZ + + + \ No newline at end of file diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 39d77274..8994c844 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -1,5 +1,6 @@ package org.openbakery +import groovy.transform.TypeChecked import org.gradle.api.logging.LogLevel import org.gradle.internal.logging.progress.ProgressLogger import org.gradle.internal.logging.progress.ProgressLoggerFactory @@ -13,6 +14,7 @@ import org.openbakery.xcode.Devices import org.openbakery.xcode.Type import org.openbakery.xcode.XcodebuildParameters +import java.util.regex.Matcher import java.util.regex.Pattern /** @@ -20,6 +22,7 @@ import java.util.regex.Pattern * Date: 15.07.13 * Time: 11:57 */ +@TypeChecked abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { XcodebuildParameters parameters = new XcodebuildParameters() @@ -116,13 +119,14 @@ 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, plistHelper)).orElseThrow { new IllegalArgumentException("Cannot resolve a valid provisioning " + - "profile for bundle identifier : " + - bundleIdentifier) + "profile for bundle identifier : " + bundleIdentifier) } } @@ -135,22 +139,51 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { .split(System.getProperty("line.separator")) .find { PATTERN.matcher(it).matches() }) .map { PATTERN.matcher(it) } - .filter { it.matches() } - .map { it.group("friendlyName") } - .orElseThrow { + .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 = new File(URI.create(getXcodeExtension().signing.certificateURI)) - assert file.exists() - return commandRunner.runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + getXcodeExtension().signing.certificatePassword]) + final String certificatePassword = getCertificatePassword() + return Optional.ofNullable(getCertificateFile()) + .filter { File file -> file.exists() } + .map { File file -> + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + certificatePassword]) + } + .orElseThrow { + new IllegalArgumentException("Cannot resolve the content of the certificate file : ${getCertificateFile().absolutePath}") + } + + } + + private File getCertificateFile() { + return new File(URI.create(getCertificateString())) + } + + private String getCertificateString() throws IllegalArgumentException { + return Optional.ofNullable(getXcodeExtension().signing.certificateURI) + .filter { String it -> it != null && !it.isEmpty() } + .orElseThrow { + new IllegalArgumentException("The certificateURI value is null or empty : " + getXcodeExtension().signing.certificateURI) + } + } + + private String getCertificatePassword() { + return Optional.ofNullable(getXcodeExtension().signing.certificatePassword) + .filter { it != null && !it.isEmpty() } + .orElseThrow { + new IllegalArgumentException("The signing certificate password is not defined") + } } } diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index fa5aa009..c618d477 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -15,6 +15,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader private final File outputFile + public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" @@ -32,7 +33,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) - this.description = "Prepare the archive configuration file" + this.description = DESCRIPTION this.outputFile = PathHelper.resolveXcConfigFile(project) } @@ -62,7 +63,8 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) Optional.ofNullable(getXcodeExtension().signing.entitlementsFile) - .ifPresent(new Consumer() { + .filter { File file -> file.exists() } + .ifPresent(new Consumer() { @Override void accept(File file) { append(KEY_CODE_SIGN_ENTITLEMENTS, file.absolutePath) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 735c8fd3..c1655964 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -19,6 +19,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private ProvisioningProfileReader reader + public static final String DESCRIPTION = "Package the IPA from the generate archive by using Xcodebuild" public static final String NAME = "packageWithXcodeBuild" private static final String PLIST_KEY_METHOD = "method" @@ -27,17 +28,20 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { private static final String PLIST_KEY_PROVISIONING_PROFILE = "provisioningProfiles" private static final String PLIST_KEY_SIGNING_CERTIFICATE = "signingCertificate" private static final String PLIST_VALUE_SIGNING_METHOD_MANUAL = "manual" - + private static final String FILE_EXPORT_OPTIONS_PLIST = "exportOptions.plist" PackageTaskIosAndTvOS() { super() + description = DESCRIPTION + dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) + onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { @@ -47,6 +51,11 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { }) } + @Override + File getProvisioningFile() { + return super.getProvisioningFile() + } + @Input boolean getBitCode() { boolean result = getXcodeExtension().bitcode @@ -69,6 +78,12 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { return super.getBundleIdentifier() } + @Input + @Override + String getSignatureFriendlyName() { + return super.getSignatureFriendlyName() + } + @Input SigningMethod getMethod() { return Optional.ofNullable(getXcodeExtension().getSigning().method) @@ -78,7 +93,16 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input String getScheme() { return Optional.ofNullable(getXcodeExtension().scheme) - .orElseThrow { new IllegalArgumentException("Invalid signing method") } + .orElseThrow { new IllegalArgumentException("Invalid scheme") } + } + + @Input + Map getProvisioningMap() { + setupProvisioningProfileReader() + + HashMap map = new HashMap<>() + map.put(reader.getApplicationIdentifier(), reader.getName()) + return map } @InputDirectory @@ -95,20 +119,21 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @OutputFile File getExportOptionsPlistFile() { - return new File(project.buildDir, "exportOptions.plist") + return new File(project.buildDir, FILE_EXPORT_OPTIONS_PLIST) } @TaskAction private void packageArchive() { assert getArchiveFile().exists() && getArchiveFile().isDirectory() - setupProvisioningProfileReader() generateExportOptionPlist() packageIt() } private void setupProvisioningProfileReader() { - reader = new ProvisioningProfileReader(getProvisioningFile() - , commandRunner) + if (reader == null) { + reader = new ProvisioningProfileReader(getProvisioningFile(), + commandRunner) + } } private void generateExportOptionPlist() { @@ -121,11 +146,9 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { getMethod().value) // Provisioning profiles map list - HashMap map = new HashMap<>() - map.put(reader.getApplicationIdentifier(), reader.getName()) plistHelper.addDictForPlist(file, PLIST_KEY_PROVISIONING_PROFILE, - map) + getProvisioningMap()) // Certificate name addStringValueForPlist(PLIST_KEY_SIGNING_CERTIFICATE, diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj new file mode 100644 index 00000000..adf3a056 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj @@ -0,0 +1,325 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + BF39E2F1209C51590086CBD3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF39E2F0209C51590086CBD3 /* AppDelegate.swift */; }; + BF39E2F3209C51590086CBD3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF39E2F2209C51590086CBD3 /* ViewController.swift */; }; + BF39E2F6209C51590086CBD3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F4209C51590086CBD3 /* Main.storyboard */; }; + BF39E2F8209C51590086CBD3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F7209C51590086CBD3 /* Assets.xcassets */; }; + BF39E2FB209C51590086CBD3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + BF39E2ED209C51590086CBD3 /* functionaltestproject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = functionaltestproject.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BF39E2F0209C51590086CBD3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + BF39E2F2209C51590086CBD3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + BF39E2F5209C51590086CBD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + BF39E2F7209C51590086CBD3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + BF39E2FA209C51590086CBD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + BF39E2FC209C51590086CBD3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BF39E2EA209C51590086CBD3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BF39E2E4209C51590086CBD3 = { + isa = PBXGroup; + children = ( + BF39E2EF209C51590086CBD3 /* functionaltestproject */, + BF39E2EE209C51590086CBD3 /* Products */, + ); + sourceTree = ""; + }; + BF39E2EE209C51590086CBD3 /* Products */ = { + isa = PBXGroup; + children = ( + BF39E2ED209C51590086CBD3 /* functionaltestproject.app */, + ); + name = Products; + sourceTree = ""; + }; + BF39E2EF209C51590086CBD3 /* functionaltestproject */ = { + isa = PBXGroup; + children = ( + BF39E2F0209C51590086CBD3 /* AppDelegate.swift */, + BF39E2F2209C51590086CBD3 /* ViewController.swift */, + BF39E2F4209C51590086CBD3 /* Main.storyboard */, + BF39E2F7209C51590086CBD3 /* Assets.xcassets */, + BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */, + BF39E2FC209C51590086CBD3 /* Info.plist */, + ); + path = functionaltestproject; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BF39E2EC209C51590086CBD3 /* functionaltestproject */ = { + isa = PBXNativeTarget; + buildConfigurationList = BF39E2FF209C51590086CBD3 /* Build configuration list for PBXNativeTarget "functionaltestproject" */; + buildPhases = ( + BF39E2E9209C51590086CBD3 /* Sources */, + BF39E2EA209C51590086CBD3 /* Frameworks */, + BF39E2EB209C51590086CBD3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = functionaltestproject; + productName = functionaltestproject; + productReference = BF39E2ED209C51590086CBD3 /* functionaltestproject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BF39E2E5209C51590086CBD3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = Massive; + TargetAttributes = { + BF39E2EC209C51590086CBD3 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = BF39E2E8209C51590086CBD3 /* Build configuration list for PBXProject "functionaltestproject" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BF39E2E4209C51590086CBD3; + productRefGroup = BF39E2EE209C51590086CBD3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BF39E2EC209C51590086CBD3 /* functionaltestproject */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BF39E2EB209C51590086CBD3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF39E2FB209C51590086CBD3 /* LaunchScreen.storyboard in Resources */, + BF39E2F8209C51590086CBD3 /* Assets.xcassets in Resources */, + BF39E2F6209C51590086CBD3 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BF39E2E9209C51590086CBD3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF39E2F3209C51590086CBD3 /* ViewController.swift in Sources */, + BF39E2F1209C51590086CBD3 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + BF39E2F4209C51590086CBD3 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BF39E2F5209C51590086CBD3 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BF39E2FA209C51590086CBD3 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + BF39E2FD209C51590086CBD3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + BF39E2FE209C51590086CBD3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BF39E300209C51590086CBD3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = functionaltestproject/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.functionaltestproject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BF39E301209C51590086CBD3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = functionaltestproject/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.functionaltestproject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BF39E2E8209C51590086CBD3 /* Build configuration list for PBXProject "functionaltestproject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF39E2FD209C51590086CBD3 /* Debug */, + BF39E2FE209C51590086CBD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BF39E2FF209C51590086CBD3 /* Build configuration list for PBXNativeTarget "functionaltestproject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF39E300209C51590086CBD3 /* Debug */, + BF39E301209C51590086CBD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BF39E2E5209C51590086CBD3 /* Project object */; +} diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..b353243c --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift new file mode 100644 index 00000000..9aa25a3f --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// functionaltestproject +// +// Created by Johann Martinache on 04/05/2018. +// Copyright © 2018 Massive. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..1d060ed2 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f83f6fd5 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard new file mode 100644 index 00000000..03c13c22 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist new file mode 100644 index 00000000..16be3b68 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift new file mode 100644 index 00000000..ff131f11 --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift @@ -0,0 +1,25 @@ +// +// ViewController.swift +// functionaltestproject +// +// Created by Johann Martinache on 04/05/2018. +// Copyright © 2018 Massive. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + +} + diff --git a/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision b/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision new file mode 100644 index 00000000..a6462cef --- /dev/null +++ b/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision @@ -0,0 +1,42 @@ +// a Dummy Mobile Provistioning File to test the ProvisioningProfileIDReader + + + + ApplicationIdentifierPrefix + + AAAAAAAAAAA + + CreationDate + 2011-06-16T08:57:51Z + DeveloperCertificates + + + + + Entitlements + + application-identifier + AAAAAAAAAAA.org.openbakery.test.Example.* + get-task-allow + + keychain-access-groups + + AAAAAAAAAAA.* + + + ExpirationDate + 2079-07-04T08:57:51Z + Name + ad hoc + ProvisionedDevices + + 1234asdf + + TimeToLive + 24855 + UUID + XXXXFFFF-AAAA-BBBB-CCCC-DDDDEEEEFFFF + Version + 1 + + \ No newline at end of file diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy new file mode 100644 index 00000000..93f25f46 --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy @@ -0,0 +1,48 @@ +package org.openbakery.packaging + +import org.gradle.testkit.runner.GradleRunner +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class PackageTaskIosAndTvOSTest extends Specification { + + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + List pluginClasspath + + File buildFile + + 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) } + } + + def "The task list should contain the task"() { + given: + buildFile << """ + plugins { + id 'org.openbakery.xcode-plugin' + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('tasks') + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.output.contains(PackageTaskIosAndTvOS.NAME + + " - " + + PackageTaskIosAndTvOS.DESCRIPTION) + } +} From 28b42061b08a4c4b1688f170a021344917722fdf Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 4 May 2018 15:46:24 +0100 Subject: [PATCH 074/121] Remove the unused datas --- .../project.pbxproj | 325 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../functionaltestproject/AppDelegate.swift | 46 --- .../AppIcon.appiconset/Contents.json | 93 ----- .../Base.lproj/LaunchScreen.storyboard | 25 -- .../Base.lproj/Main.storyboard | 24 -- .../functionaltestproject/Info.plist | 45 --- .../ViewController.swift | 25 -- .../openbakery-wildcard.mobileprovision | 42 --- 10 files changed, 640 deletions(-) delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist delete mode 100644 plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift delete mode 100644 plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj deleted file mode 100644 index adf3a056..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.pbxproj +++ /dev/null @@ -1,325 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 48; - objects = { - -/* Begin PBXBuildFile section */ - BF39E2F1209C51590086CBD3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF39E2F0209C51590086CBD3 /* AppDelegate.swift */; }; - BF39E2F3209C51590086CBD3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF39E2F2209C51590086CBD3 /* ViewController.swift */; }; - BF39E2F6209C51590086CBD3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F4209C51590086CBD3 /* Main.storyboard */; }; - BF39E2F8209C51590086CBD3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F7209C51590086CBD3 /* Assets.xcassets */; }; - BF39E2FB209C51590086CBD3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - BF39E2ED209C51590086CBD3 /* functionaltestproject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = functionaltestproject.app; sourceTree = BUILT_PRODUCTS_DIR; }; - BF39E2F0209C51590086CBD3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - BF39E2F2209C51590086CBD3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - BF39E2F5209C51590086CBD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - BF39E2F7209C51590086CBD3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - BF39E2FA209C51590086CBD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - BF39E2FC209C51590086CBD3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - BF39E2EA209C51590086CBD3 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - BF39E2E4209C51590086CBD3 = { - isa = PBXGroup; - children = ( - BF39E2EF209C51590086CBD3 /* functionaltestproject */, - BF39E2EE209C51590086CBD3 /* Products */, - ); - sourceTree = ""; - }; - BF39E2EE209C51590086CBD3 /* Products */ = { - isa = PBXGroup; - children = ( - BF39E2ED209C51590086CBD3 /* functionaltestproject.app */, - ); - name = Products; - sourceTree = ""; - }; - BF39E2EF209C51590086CBD3 /* functionaltestproject */ = { - isa = PBXGroup; - children = ( - BF39E2F0209C51590086CBD3 /* AppDelegate.swift */, - BF39E2F2209C51590086CBD3 /* ViewController.swift */, - BF39E2F4209C51590086CBD3 /* Main.storyboard */, - BF39E2F7209C51590086CBD3 /* Assets.xcassets */, - BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */, - BF39E2FC209C51590086CBD3 /* Info.plist */, - ); - path = functionaltestproject; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - BF39E2EC209C51590086CBD3 /* functionaltestproject */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF39E2FF209C51590086CBD3 /* Build configuration list for PBXNativeTarget "functionaltestproject" */; - buildPhases = ( - BF39E2E9209C51590086CBD3 /* Sources */, - BF39E2EA209C51590086CBD3 /* Frameworks */, - BF39E2EB209C51590086CBD3 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = functionaltestproject; - productName = functionaltestproject; - productReference = BF39E2ED209C51590086CBD3 /* functionaltestproject.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - BF39E2E5209C51590086CBD3 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0920; - ORGANIZATIONNAME = Massive; - TargetAttributes = { - BF39E2EC209C51590086CBD3 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = BF39E2E8209C51590086CBD3 /* Build configuration list for PBXProject "functionaltestproject" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = BF39E2E4209C51590086CBD3; - productRefGroup = BF39E2EE209C51590086CBD3 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - BF39E2EC209C51590086CBD3 /* functionaltestproject */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - BF39E2EB209C51590086CBD3 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF39E2FB209C51590086CBD3 /* LaunchScreen.storyboard in Resources */, - BF39E2F8209C51590086CBD3 /* Assets.xcassets in Resources */, - BF39E2F6209C51590086CBD3 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - BF39E2E9209C51590086CBD3 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF39E2F3209C51590086CBD3 /* ViewController.swift in Sources */, - BF39E2F1209C51590086CBD3 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - BF39E2F4209C51590086CBD3 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - BF39E2F5209C51590086CBD3 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - BF39E2F9209C51590086CBD3 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - BF39E2FA209C51590086CBD3 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - BF39E2FD209C51590086CBD3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.2; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - BF39E2FE209C51590086CBD3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.2; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - BF39E300209C51590086CBD3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = functionaltestproject/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.functionaltestproject; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BF39E301209C51590086CBD3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = functionaltestproject/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = gradle.xcode.test.functionaltestproject; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - BF39E2E8209C51590086CBD3 /* Build configuration list for PBXProject "functionaltestproject" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF39E2FD209C51590086CBD3 /* Debug */, - BF39E2FE209C51590086CBD3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF39E2FF209C51590086CBD3 /* Build configuration list for PBXNativeTarget "functionaltestproject" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF39E300209C51590086CBD3 /* Debug */, - BF39E301209C51590086CBD3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = BF39E2E5209C51590086CBD3 /* Project object */; -} diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index b353243c..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift deleted file mode 100644 index 9aa25a3f..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/AppDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.swift -// functionaltestproject -// -// Created by Johann Martinache on 04/05/2018. -// Copyright © 2018 Massive. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 1d060ed2..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f83f6fd5..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard deleted file mode 100644 index 03c13c22..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist deleted file mode 100644 index 16be3b68..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift b/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift deleted file mode 100644 index ff131f11..00000000 --- a/plugin/src/test/Resource/functionaltestproject/functionaltestproject/ViewController.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// ViewController.swift -// functionaltestproject -// -// Created by Johann Martinache on 04/05/2018. -// Copyright © 2018 Massive. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - -} - diff --git a/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision b/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision deleted file mode 100644 index a6462cef..00000000 --- a/plugin/src/test/Resource/functionaltestproject/openbakery-wildcard.mobileprovision +++ /dev/null @@ -1,42 +0,0 @@ -// a Dummy Mobile Provistioning File to test the ProvisioningProfileIDReader - - - - ApplicationIdentifierPrefix - - AAAAAAAAAAA - - CreationDate - 2011-06-16T08:57:51Z - DeveloperCertificates - - - - - Entitlements - - application-identifier - AAAAAAAAAAA.org.openbakery.test.Example.* - get-task-allow - - keychain-access-groups - - AAAAAAAAAAA.* - - - ExpirationDate - 2079-07-04T08:57:51Z - Name - ad hoc - ProvisionedDevices - - 1234asdf - - TimeToLive - 24855 - UUID - XXXXFFFF-AAAA-BBBB-CCCC-DDDDEEEEFFFF - Version - 1 - - \ No newline at end of file From 6a8c661462c5b10f8fca01037cf35415ea4e3bac Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 4 May 2018 16:02:48 +0100 Subject: [PATCH 075/121] Adjust the unit tests --- .../PrepareXcodeArchivingFunctionalTest.groovy | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy index 26b4ea2e..28d12718 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -91,7 +91,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { .withPluginClasspath(pluginClasspath) .buildAndFail() - then: + then: "The build should fail due to invalidate configuration" result.output.contains("> Cannot resolve a valid provisioning profile for bundle identifier : " + exceptionValue) @@ -120,7 +120,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { .withPluginClasspath(pluginClasspath) .buildAndFail() - then: + then: "The build should fail due to invalidate configuration" result.output.contains("The signing certificate password is not defined") } @@ -161,7 +161,8 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { then: "The task should complete without error" - result.task(":" + PrepareXcodeArchivingTask.NAME).outcome == TaskOutcome.SUCCESS + result.task(":" + PrepareXcodeArchivingTask.NAME) + .outcome == TaskOutcome.SUCCESS and: "The archive xcconfig file should be properly generated and populated from configured values" @@ -169,6 +170,8 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { + PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.ARCHIVE_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)") From 3ea983cb5f07f28eb119f8e18fa18bdadb0c6b7f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 8 May 2018 14:00:03 +0100 Subject: [PATCH 076/121] Adjustements --- .../src/main/groovy/org/openbakery/util/PathHelper.groovy | 8 ++++---- .../org/openbakery}/PackageTaskIosAndTvOSTest.groovy | 3 ++- .../openbakery/PrepareXcodeArchivingFunctionalTest.groovy | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) rename plugin/src/{test/groovy/org/openbakery/packaging => functionalTest/groovy/org/openbakery}/PackageTaskIosAndTvOSTest.groovy (93%) diff --git a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy index c6fffffc..b7a96265 100644 --- a/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy +++ b/libxcode/src/main/groovy/org/openbakery/util/PathHelper.groovy @@ -12,8 +12,8 @@ class PathHelper { public static final String IPHONE_OS = "iphoneos" public static final String FOLDER_ARCHIVE = "archive" public static final String FOLDER_PACKAGE = "package" - public static final String ARCHIVE_FILE_NAME = "archive.xcconfig" - public static final String EXTENSION_XC_ARCHIVE = ".xcarchive" + public static final String GENERATED_XCARCHIVE_FILE_NAME = "archive.xcconfig" + public static final String EXTENSION_XCARCHIVE = ".xcarchive" static File resolvePath(Type type, boolean simulator, @@ -82,7 +82,7 @@ class PathHelper { static File resolveArchiveFile(Project project, String scheme) { - return new File(resolveArchiveFolder(project), scheme + EXTENSION_XC_ARCHIVE) + return new File(resolveArchiveFolder(project), scheme + EXTENSION_XCARCHIVE) } static File resolveArchivingLogFile(Project project) { @@ -90,7 +90,7 @@ class PathHelper { } static File resolveXcConfigFile(Project project) { - return new File(resolveArchiveFolder(project), ARCHIVE_FILE_NAME) + return new File(resolveArchiveFolder(project), GENERATED_XCARCHIVE_FILE_NAME) } static File resolvePackageFolder(Project project) { diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy similarity index 93% rename from plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy rename to plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy index 93f25f46..83c7d69b 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskIosAndTvOSTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PackageTaskIosAndTvOSTest.groovy @@ -1,8 +1,9 @@ -package org.openbakery.packaging +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 { diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy index 28d12718..bbbf3b4d 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -168,7 +168,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { File outputFile = new File(testProjectDir.root, "build/" + PathHelper.FOLDER_ARCHIVE - + "/" + PathHelper.ARCHIVE_FILE_NAME) + + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME) outputFile.exists() From d5e1739acde9f1db1d82a4d5d079cb54b9895b7f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 9 May 2018 13:37:33 +0100 Subject: [PATCH 077/121] Convert the xcodeversion to a property --- .../org/openbakery/AbstractXcodeTask.groovy | 18 ++++---- .../XcodeBuildPluginExtension.groovy | 42 +++---------------- .../packaging/PackageTaskSpecification.groovy | 6 +-- 3 files changed, 18 insertions(+), 48 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy index d2b026f8..15315d91 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy @@ -52,7 +52,6 @@ abstract class AbstractXcodeTask extends DefaultTask { security = new Security(commandRunner) } - /** * Copies a file to a new location * @@ -77,7 +76,7 @@ abstract class AbstractXcodeTask extends DefaultTask { ant.exec(failonerror: "true", - executable: 'ditto') { + executable: 'ditto') { arg(value: source.absolutePath) arg(value: destinationPath.absolutePath) } @@ -102,7 +101,7 @@ abstract class AbstractXcodeTask extends DefaultTask { } try { - ant.get(src: address, dest: toDirectory.getPath(), verbose:true) + ant.get(src: address, dest: toDirectory.getPath(), verbose: true) } catch (Exception ex) { logger.error("cannot download file from the given location: {}", address) throw ex @@ -151,7 +150,7 @@ abstract class AbstractXcodeTask extends DefaultTask { logger.debug("baseDirectory: {} ", baseDirectory) for (File file : filesToZip) { - logger.debug("create of: {}: {}", file, file.exists() ) + logger.debug("create of: {}: {}", file, file.exists()) } def arguments = [] @@ -166,8 +165,8 @@ abstract class AbstractXcodeTask extends DefaultTask { logger.debug("arguments: {}", arguments) ant.exec(failonerror: 'true', - executable: '/usr/bin/zip', - dir: baseDirectory) { + executable: '/usr/bin/zip', + dir: baseDirectory) { for (def argument : arguments) { arg(value: argument) @@ -189,7 +188,7 @@ abstract class AbstractXcodeTask extends DefaultTask { List getAppBundles(File appPath) { - ApplicationBundle applicationBundle = new ApplicationBundle(new File(appPath,project.xcodebuild.applicationBundle.name), project.xcodebuild.type, project.xcodebuild.simulator) + ApplicationBundle applicationBundle = new ApplicationBundle(new File(appPath, project.xcodebuild.applicationBundle.name), project.xcodebuild.type, project.xcodebuild.simulator) return applicationBundle.getBundles() } @@ -208,7 +207,10 @@ abstract class AbstractXcodeTask extends DefaultTask { } String getProjectXcodeVersion() { - return project.xcodebuild.xcodeVersion + return project.extensions. + getByType(XcodeBuildPluginExtension). + version. + getOrNull() } DestinationResolver getDestinationResolver() { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 8d25b748..a5a532e1 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -18,6 +18,7 @@ package org.openbakery import org.apache.commons.io.filefilter.SuffixFileFilter import org.apache.commons.lang.StringUtils import org.gradle.api.Project +import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil import org.openbakery.signing.Signing import org.openbakery.util.PathHelper @@ -27,38 +28,10 @@ import org.openbakery.xcode.* import org.slf4j.Logger import org.slf4j.LoggerFactory -/* - -^ -should be migrated to this -> and renamed to Device - -enum Devices { - PHONE(1<<0), - PAD(1<<1), - WATCH(1<<2), - TV(1<<3) - - private final int value; - - Devices(int value) { - this.value = value - } - - public int getValue() { - return value - } - - public boolean is(Devices device) { - return (this.value & device.value) > 0 - } - -} - */ - - class XcodeBuildPluginExtension { public final static KEYCHAIN_NAME_BASE = "gradle-" + final Property version private static Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) @@ -113,6 +86,9 @@ class XcodeBuildPluginExtension { public XcodeBuildPluginExtension(Project project) { this.project = project; + + this.version = project.objects.property(String) + this.signing = new Signing(project) this.variableResolver = new VariableResolver(project) commandRunner = new CommandRunner() @@ -284,14 +260,6 @@ class XcodeBuildPluginExtension { } - void setVersion(String version) { - this.xcodeVersion = version - // check if the version is valid. On creation of the Xcodebuild class an exception is thrown if the version is not valid - xcode = null - //getXcode() - } - - String getValueFromInfoPlist(key) { if (infoPlist != null) { File infoPlistFile = new File(project.projectDir, infoPlist) diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 0349dc8c..bca036b9 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -210,7 +210,7 @@ class PackageTaskSpecification extends Specification { def "swift Framework xcode 6"() { given: mockXcodeVersion() - project.xcodebuild.version = 6 + project.xcodebuild.version.set("6") FileUtils.deleteDirectory(project.projectDir) mockExampleApp(false, true, false, false) @@ -228,7 +228,7 @@ class PackageTaskSpecification extends Specification { def "SwiftSupport should be added for Appstore IPA"() { given: mockXcodeVersion() - project.xcodebuild.version = 7 + project.xcodebuild.version.set("7") FileUtils.deleteDirectory(project.projectDir) mockExampleApp(false, true, false, false) @@ -246,7 +246,7 @@ class PackageTaskSpecification extends Specification { def "SwiftSupport should not be added for AdHoc IPA"() { given: mockXcodeVersion() - project.xcodebuild.version = 7 + project.xcodebuild.version.set("7") FileUtils.deleteDirectory(project.projectDir) mockExampleApp(false, true) From 309a69e1acda6dc215dde62a701ca63d8c44da45 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 9 May 2018 13:44:04 +0100 Subject: [PATCH 078/121] Properly instantiate the signing nested extension --- .../groovy/org/openbakery/XcodeBuildPluginExtension.groovy | 6 ++++-- .../src/main/groovy/org/openbakery/signing/Signing.groovy | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index a5a532e1..50bc7268 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -32,6 +32,7 @@ class XcodeBuildPluginExtension { public final static KEYCHAIN_NAME_BASE = "gradle-" final Property version + final Signing signing private static Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) @@ -50,7 +51,7 @@ class XcodeBuildPluginExtension { Object symRoot Object sharedPrecompsDir Object derivedDataPath - Signing signing = null + def additionalParameters = null String bundleNameSuffix = null List arch = null @@ -87,9 +88,10 @@ class XcodeBuildPluginExtension { public XcodeBuildPluginExtension(Project project) { this.project = project; + this.signing = project.objects.newInstance(Signing, project) this.version = project.objects.property(String) - this.signing = new Signing(project) + this.variableResolver = new VariableResolver(project) commandRunner = new CommandRunner() plistHelper = new PlistHelper(commandRunner) diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index fcbfae27..28ce1ff4 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -4,6 +4,8 @@ import org.gradle.api.Project import org.openbakery.CommandRunner import org.openbakery.codesign.CodesignParameters +import javax.inject.Inject + /** * * @author René Pirringer @@ -40,7 +42,8 @@ class Signing { private SigningMethod method - public Signing(Project project) { + @Inject + Signing(Project project) { this.project = project; this.commandRunner = new CommandRunner() From ad7750dc1aa81849894714c136e839ee5e64b61f Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 10 May 2018 09:43:03 +0100 Subject: [PATCH 079/121] --wip-- [skip ci] --- .../openbakery/AbstractXcodeBuildTask.groovy | 41 ++++--- .../org/openbakery/AbstractXcodeTask.groovy | 22 +--- .../groovy/org/openbakery/XcodePlugin.groovy | 28 ++++- .../org/openbakery/oclint/OCLintTask.groovy | 3 +- .../signing/AbstractKeychainTask.groovy | 66 +++++----- .../signing/KeychainCleanupTask.groovy | 13 +- .../signing/KeychainCreateTask.groovy | 115 ++++++++++++------ .../signing/ProvisioningCleanupTask.groovy | 50 ++++---- .../signing/ProvisioningInstallTask.groovy | 10 +- .../org/openbakery/signing/Signing.groovy | 85 +++++-------- .../org/openbakery/util/FileUtil.groovy | 33 +++++ .../org/openbakery/util/SystemUtil.groovy | 21 ++++ .../KeychainCreateTaskSpecification.groovy | 8 +- 13 files changed, 288 insertions(+), 207 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy create mode 100644 plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 8994c844..239c887c 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -150,21 +150,18 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { private String getKeyContent() { final String certificatePassword = getCertificatePassword() - return Optional.ofNullable(getCertificateFile()) - .filter { File file -> file.exists() } - .map { File file -> - return commandRunner.runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + certificatePassword]) - } - .orElseThrow { - new IllegalArgumentException("Cannot resolve the content of the certificate file : ${getCertificateFile().absolutePath}") - } + File file = xcodeExtension.signing + .certificate + .get() + .asFile + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + certificatePassword]) } private File getCertificateFile() { @@ -172,15 +169,19 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { } private String getCertificateString() throws IllegalArgumentException { - return Optional.ofNullable(getXcodeExtension().signing.certificateURI) - .filter { String it -> it != null && !it.isEmpty() } - .orElseThrow { - new IllegalArgumentException("The certificateURI value is null or empty : " + getXcodeExtension().signing.certificateURI) - } +// return Optional.ofNullable(getXcodeExtension().signing.certificate) +// .filter { String it -> it != null && !it.isEmpty() } +// .orElseThrow { +// new IllegalArgumentException("The certificateURI value is null or empty : " + getXcodeExtension().signing.certificateURI) +// } + + return getXcodeExtension() + .signing + .certificate } private String getCertificatePassword() { - return Optional.ofNullable(getXcodeExtension().signing.certificatePassword) + return Optional.ofNullable(getXcodeExtension().signing.certificatePassword.getOrNull()) .filter { it != null && !it.isEmpty() } .orElseThrow { new IllegalArgumentException("The signing certificate password is not defined") diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy index 15315d91..8528ef94 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeTask.groovy @@ -15,20 +15,17 @@ */ package org.openbakery - import org.apache.commons.io.FilenameUtils import org.apache.commons.lang.StringUtils import org.gradle.api.DefaultTask import org.openbakery.bundle.ApplicationBundle import org.openbakery.codesign.Security import org.openbakery.simulators.SimulatorControl +import org.openbakery.util.PlistHelper import org.openbakery.xcode.DestinationResolver -import org.openbakery.xcode.Version import org.openbakery.xcode.Xcode -import org.openbakery.util.PlistHelper import java.text.SimpleDateFormat - /** * * @author René Pirringer @@ -111,23 +108,6 @@ abstract class AbstractXcodeTask extends DefaultTask { return destinationFile.absolutePath } - def getOSVersion() { - Version result = new Version() - String versionString = System.getProperty("os.version") - Scanner scanner = new Scanner(versionString).useDelimiter("\\.") - if (scanner.hasNext()) { - result.major = scanner.nextInt() - } - if (scanner.hasNext()) { - result.minor = scanner.nextInt() - } - if (scanner.hasNext()) { - result.maintenance = scanner.nextInt(); - } - return result - } - - def createZip(File fileToZip) { File zipFile = new File(fileToZip.parentFile, FilenameUtils.getBaseName(fileToZip.getName()) + ".zip") createZip(zipFile, zipFile.parentFile, fileToZip); diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 5fd1107c..d5a3e727 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -36,6 +36,7 @@ import org.openbakery.carthage.CarthageUpdateTask import org.openbakery.cocoapods.CocoapodsBootstrapTask import org.openbakery.cocoapods.CocoapodsInstallTask import org.openbakery.cocoapods.CocoapodsUpdateTask +import org.openbakery.codesign.Security import org.openbakery.configuration.XcodeConfigTask import org.openbakery.coverage.CoverageCleanTask import org.openbakery.coverage.CoveragePluginExtension @@ -133,11 +134,16 @@ class XcodePlugin implements Plugin { public static final String SDK_IPHONESIMULATOR = "iphonesimulator" + private XcodeBuildPluginExtension xcodeBuildPluginExtension + + private CommandRunner commandRunner + private Security securityTool + void apply(Project project) { project.getPlugins().apply(BasePlugin.class); System.setProperty("java.awt.headless", "true"); - + setupTools(project) configureExtensions(project) configureClean(project) configureBuild(project) @@ -162,6 +168,10 @@ class XcodePlugin implements Plugin { configureProperties(project) } + void setupTools(Project project) { + this.commandRunner = new CommandRunner() + this.securityTool = new Security(commandRunner) + } void configureProperties(Project project) { @@ -424,7 +434,10 @@ class XcodePlugin implements Plugin { void configureExtensions(Project project) { - project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) + xcodeBuildPluginExtension = project.extensions.create("xcodebuild", + XcodeBuildPluginExtension, + project) + project.extensions.create("infoplist", InfoPlistExtension) project.extensions.create("hockeykit", HockeyKitPluginExtension, project) project.extensions.create("appstore", AppstorePluginExtension, project) @@ -503,7 +516,16 @@ class XcodePlugin implements Plugin { } private void configureKeychain(Project project) { - project.task(KEYCHAIN_CREATE_TASK_NAME, type: KeychainCreateTask, group: XCODE_GROUP_NAME) + project.tasks.create(KEYCHAIN_CREATE_TASK_NAME, KeychainCreateTask.class) { + it.group = XCODE_GROUP_NAME + it.certificateFile.set(xcodeBuildPluginExtension.signing.certificate) + it.certificatePassword.set(xcodeBuildPluginExtension.signing.certificatePassword) + it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) + it.keyChainFile.set(xcodeBuildPluginExtension.signing.keyChainFile) + it.keychainTimeout.set(xcodeBuildPluginExtension.signing.timeout) + it.security.set(securityTool) + } + project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) } diff --git a/plugin/src/main/groovy/org/openbakery/oclint/OCLintTask.groovy b/plugin/src/main/groovy/org/openbakery/oclint/OCLintTask.groovy index c0d75c1f..6b725c4e 100644 --- a/plugin/src/main/groovy/org/openbakery/oclint/OCLintTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/oclint/OCLintTask.groovy @@ -3,6 +3,7 @@ package org.openbakery.oclint import org.apache.commons.io.FilenameUtils import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeTask +import org.openbakery.util.SystemUtil class OCLintTask extends AbstractXcodeTask { @@ -37,7 +38,7 @@ class OCLintTask extends AbstractXcodeTask { def getDownloadURL() { - if (getOSVersion().minor >= 12) { + if (SystemUtil.getOsVersion().minor >= 12) { return "https://github.com/oclint/oclint/releases/download/v0.13/oclint-0.13-x86_64-darwin-17.0.0.tar.gz" } return "https://github.com/oclint/oclint/releases/download/v0.13/oclint-0.13-x86_64-darwin-16.7.0.tar.gz" diff --git a/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy index 506483bf..8119f081 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy @@ -1,52 +1,54 @@ package org.openbakery.signing -import org.apache.commons.lang.StringUtils -import org.openbakery.AbstractXcodeTask -import org.openbakery.XcodeBuildPluginExtension +import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.OutputFile import org.openbakery.codesign.Security -/** - * Created with IntelliJ IDEA. - * User: rene - * Date: 23.08.13 - * Time: 11:39 - * To change this template use File | Settings | File Templates. - */ -abstract class AbstractKeychainTask extends AbstractXcodeTask { +@CompileStatic +abstract class AbstractKeychainTask extends DefaultTask { - Security security + @OutputFile + final RegularFileProperty keyChainFile = newOutputFile() + + final Property security = project.objects.property(Security) + final DirectoryProperty outputDirectory = newOutputDirectory() AbstractKeychainTask() { - security = new Security(commandRunner) + setupGarbageCleaner() } - List getKeychainList() { - return security.getKeychainList() + return security.get().getKeychainList() } - def setKeychainList(List keychainList) { - security.setKeychainList(keychainList) + void setKeychainList(List keychainList) { + security.get().setKeychainList(keychainList) } - /** - * remove all gradle keychains from the keychain search list - * @return - */ - def removeGradleKeychainsFromSearchList() { - ListkeychainList = getKeychainList() - logger.debug("project.xcodebuild.signing.keychain should not be removed: {}", project.xcodebuild.signing.keychainPathInternal) - if (project.xcodebuild.signing.keychainPathInternal != null) { - keychainList.remove(project.xcodebuild.signing.keychainPathInternal) + void removeGradleKeychainsFromSearchList() { + if (keyChainFile.present) { + logger.info("Remove the temporary keychain from search list") + List list = getKeychainList() + list.remove(keyChainFile.get()) + setKeychainList(list) } - setKeychainList(keychainList) } - def cleanupKeychain() { - project.xcodebuild.signing.signingDestinationRoot.deleteDir() - removeGradleKeychainsFromSearchList() + void deleteTemporaryKeyChainFile() { + if (keyChainFile.present) { + logger.info("Delete the temporary keychain file") + keyChainFile.get().asFile.delete() + } } - - + private void setupGarbageCleaner() { + project.gradle.buildFinished { + removeGradleKeychainsFromSearchList() + deleteTemporaryKeyChainFile() + } + } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy index 3077dcbd..da21f8ee 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy @@ -16,7 +16,6 @@ package org.openbakery.signing import org.gradle.api.tasks.TaskAction -import org.openbakery.XcodeBuildPluginExtension class KeychainCleanupTask extends AbstractKeychainTask { @@ -29,11 +28,11 @@ class KeychainCleanupTask extends AbstractKeychainTask { @TaskAction def clean() { - if (project.xcodebuild.signing.keychain) { - logger.debug("Nothing to cleanup") - return - } - cleanupKeychain() +// if (project.xcodebuild.signing.keychain) { +// logger.debug("Nothing to cleanup") +// return +// } +// cleanupKeychain() } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 01ae15a6..4abe24d7 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -15,70 +15,109 @@ */ package org.openbakery.signing +import groovy.transform.CompileStatic +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.TaskAction -import org.gradle.api.InvalidUserDataException -import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin +import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.util.FileUtil +import org.openbakery.util.SystemUtil +import org.openbakery.xcode.Version +@CompileStatic class KeychainCreateTask extends AbstractKeychainTask { + @InputFile + final RegularFileProperty certificateFile = newInputFile() + + @Input + final Property certificatePassword = project.objects.property(String) + + @Input + final Property keychainTimeout = project.objects.property(Integer) + + private File temporaryCertificateFile KeychainCreateTask() { super() this.description = "Create a keychain that is used for signing the app" - } + onlyIf { + XcodeBuildPluginExtension extension = project + .getExtensions() + .findByType(XcodeBuildPluginExtension) - @TaskAction - def create() { + Signing signing = extension.signing + if (!signing.certificate.present) + logger.warn("Not signing certificate defined, will skip the keychain creation") + if (!signing.certificatePassword.present) + logger.warn("Not signing certificate password defined, will skip the keychain creation") - if (project.xcodebuild.signing.keychain) { - if (!project.xcodebuild.signing.keychain.exists()) { - throw new IllegalStateException("Keychain not found: " + project.xcodebuild.signing.keychain.absolutePath) + if (keyChainFile.present && keyChainFile.asFile.get().exists()) { + logger.debug("Using keychain : " + keyChainFile.get()) } - logger.debug("Using keychain {}", project.xcodebuild.signing.keychain) - logger.debug("Internal keychain {}", project.xcodebuild.signing.keychainPathInternal) - return - } - if (project.xcodebuild.signing.certificateURI == null) { - logger.debug("not certificateURI specifed so do not create the keychain"); - return - } - - - if (project.xcodebuild.signing.certificatePassword == null) { - throw new InvalidUserDataException("Property project.xcodebuild.signing.certificatePassword is missing") + return (signing.certificate.present && + signing.certificatePassword.present) || + (keyChainFile.present && keyChainFile.asFile.get().exists()) } + } - // first cleanup old keychain - cleanupKeychain() + @TaskAction + void create() { + createTemporaryCertificateFile() + createKeyChainAndImportCertificate() + addKeyChainToThePartitionList() + setupOptionalTimeout() + } - def certificateFile = download(project.xcodebuild.signing.signingDestinationRoot, project.xcodebuild.signing.certificateURI) + private void createTemporaryCertificateFile() { + temporaryCertificateFile = FileUtil.download(project, + outputDirectory.asFile.get(), + certificateFile.asFile.get().toURI().toString()) - File keychain = project.xcodebuild.signing.keychainPathInternal + // Delete the temporary file on completion + project.gradle.buildFinished { + if (temporaryCertificateFile.exists()) { + temporaryCertificateFile.delete() + } + } + } - security.createKeychain(keychain, project.xcodebuild.signing.keychainPassword) - security.importCertificate(new File(certificateFile), project.xcodebuild.signing.certificatePassword, keychain) + private void createKeyChainAndImportCertificate() { + security.get() + .createKeychain(keyChainFile.asFile.getOrNull(), + certificatePassword.get()) + security.get() + .importCertificate(temporaryCertificateFile, + certificatePassword.get(), + keyChainFile.asFile.get()) + } - if (getOSVersion().minor >= 9) { + private void addKeyChainToThePartitionList() { + Version systemVersion = SystemUtil.getOsVersion() + if (systemVersion.minor >= 9) { List keychainList = getKeychainList() - keychainList.add(keychain) + keychainList.add(keyChainFile.asFile.get()) setKeychainList(keychainList) } - if (getOSVersion().minor >= 12) { - security.setPartitionList(keychain, project.xcodebuild.signing.keychainPassword) + if (systemVersion.minor >= 12) { + security.get().setPartitionList(keyChainFile.asFile.get(), + certificatePassword.get()) } - // Set a custom timeout on the keychain if requested - if (project.xcodebuild.signing.timeout != null) { - security.setTimeout(project.xcodebuild.signing.timeout, keychain) - } } - - -} \ No newline at end of file + private void setupOptionalTimeout() { + if (keychainTimeout.present) { + security.get() + .setTimeout(keychainTimeout.get(), + keyChainFile.asFile.get()) + } + } +} diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy index e7023cc8..52829982 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy @@ -26,29 +26,29 @@ class ProvisioningCleanupTask extends AbstractXcodeTask { @TaskAction def clean() { - if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { - logger.debug("deleting {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) - project.xcodebuild.signing.mobileProvisionDestinationRoot.deleteDir() - - if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { - logger.error("error deleting provisioning: {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) - } - } else { - logger.debug("Provisioning destination cleanup skipped because the destination directory does not exit") - } - - File mobileprovisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/") - - if (mobileprovisionPath.exists()) { - // find all the broken profile links that where created by this plugin - String profileLinksToDelete = commandRunner.runWithResult(["find", "-L", mobileprovisionPath.absolutePath, "-name", ProvisioningInstallTask.PROVISIONING_NAME_BASE +"*", "-type", "l"]); - String[] profiles = profileLinksToDelete.split("\n") - for (String profile : profiles) { - logger.debug("profile to delete {}", profile) - new File(profile).delete(); - } - } else { - logger.debug("nothing to cleanup") - } +// if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { +// logger.debug("deleting {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) +// project.xcodebuild.signing.mobileProvisionDestinationRoot.deleteDir() +// +// if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { +// logger.error("error deleting provisioning: {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) +// } +// } else { +// logger.debug("Provisioning destination cleanup skipped because the destination directory does not exit") +// } +// +// File mobileprovisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/") +// +// if (mobileprovisionPath.exists()) { +// // find all the broken profile links that where created by this plugin +// String profileLinksToDelete = commandRunner.runWithResult(["find", "-L", mobileprovisionPath.absolutePath, "-name", ProvisioningInstallTask.PROVISIONING_NAME_BASE +"*", "-type", "l"]); +// String[] profiles = profileLinksToDelete.split("\n") +// for (String profile : profiles) { +// logger.debug("profile to delete {}", profile) +// new File(profile).delete(); +// } +// } else { +// logger.debug("nothing to cleanup") +// } } -} \ No newline at end of file +} diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index f6512c0c..0474a854 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -20,13 +20,13 @@ import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.util.FileUtil class ProvisioningInstallTask extends AbstractXcodeTask { public final static PROVISIONING_NAME_BASE = "gradle-" - ProvisioningInstallTask() { super() dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) @@ -40,7 +40,7 @@ class ProvisioningInstallTask extends AbstractXcodeTask { provisionPath.mkdirs() } - File mobileProvisionFileLinkToLibrary = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/" + mobileProvisionFile.getName()); + File mobileProvisionFileLinkToLibrary = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/" + mobileProvisionFile.getName()); if (mobileProvisionFileLinkToLibrary.exists()) { mobileProvisionFileLinkToLibrary.delete() } @@ -60,9 +60,9 @@ class ProvisioningInstallTask extends AbstractXcodeTask { } for (String mobileProvisionURI : project.xcodebuild.signing.mobileProvisionURI) { - def mobileProvisionFile = download(project.xcodebuild.signing.mobileProvisionDestinationRoot, mobileProvisionURI) - - + def mobileProvisionFile = FileUtil.download(project, + project.xcodebuild.signing.mobileProvisionDestinationRoot, + mobileProvisionURI).absolutePath ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(new File(mobileProvisionFile), this.commandRunner, this.plistHelper) diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 28ce1ff4..cc403992 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -1,27 +1,33 @@ package org.openbakery.signing import org.gradle.api.Project +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Internal import org.openbakery.CommandRunner import org.openbakery.codesign.CodesignParameters import javax.inject.Inject -/** - * - * @author René Pirringer - * - */ class Signing { + final DirectoryProperty signingDestinationRoot = project.layout.directoryProperty() + final Property certificatePassword + final Property timeout = project.objects.property(Integer) + final RegularFileProperty certificate + final RegularFileProperty keychain = project.layout.fileProperty() + final RegularFileProperty keyChainFile = project.layout.fileProperty() + + @Internal + Object keychainPathInternal + public final static KEYCHAIN_NAME_BASE = "gradle-" String identity - String certificateURI - String certificatePassword + List mobileProvisionURI = null String keychainPassword = "This_is_the_default_keychain_password" - File keychain - Integer timeout = 3600 String plugin Object entitlementsFile @@ -30,76 +36,47 @@ class Signing { /** * internal parameters */ - Object signingDestinationRoot - Object keychainPathInternal - final Project project - final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" + private final Project project + private final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" CommandRunner commandRunner - - Object mobileProvisionDestinationRoot List mobileProvisionFile = new ArrayList() private SigningMethod method @Inject Signing(Project project) { - this.project = project; + this.project = project + this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) + this.certificate = project.layout.fileProperty() + this.certificatePassword = project.objects.property(String) this.commandRunner = new CommandRunner() - - this.signingDestinationRoot = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("codesign") - } - - this.keychainPathInternal = { - if (this.keychain != null) { - return this.keychain - } - return new File(this.signingDestinationRoot, keychainName) - } - - this.mobileProvisionDestinationRoot = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("provision") - } - + this.keyChainFile.set(signingDestinationRoot.file(keychainName)) + this.timeout.set(3600) } void setKeychain(Object keychain) { if (keychain instanceof String && keychain.matches("^~/.*")) { keychain = keychain.replaceFirst("~", System.getProperty('user.home')) } - this.keychain = project.file(keychain) + this.keychain.set(project.file(keychain)) } public void setMethod(String method) { this.method = SigningMethod.fromString(method) - .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") } + .orElseThrow { + new IllegalArgumentException("Method : $method is not a valid export method") + } } SigningMethod getMethod() { return method } - File getSigningDestinationRoot() { - return project.file(signingDestinationRoot) - } - - void setSigningDestinationRoot(Object keychainDestinationRoot) { - this.signingDestinationRoot = keychainDestinationRoot - } - File getKeychainPathInternal() { return project.file(keychainPathInternal) } - File getMobileProvisionDestinationRoot() { - return project.file(mobileProvisionDestinationRoot) - } - - void setMobileProvisionDestinationRoot(Object mobileProvisionDestinationRoot) { - this.mobileProvisionDestinationRoot = mobileProvisionDestinationRoot - } - void setMobileProvisionURI(Object mobileProvisionURI) { if (mobileProvisionURI instanceof List) { this.mobileProvisionURI = mobileProvisionURI; @@ -146,6 +123,10 @@ class Signing { } + void setCertificateURI(String uri) { + certificate.set(new File(new URI(uri))) + } + @Override public String toString() { if (this.keychain != null) { @@ -157,8 +138,8 @@ class Signing { } return "Signing{" + " identity='" + identity + '\'' + - ", certificateURI='" + certificateURI + '\'' + - ", certificatePassword='" + certificatePassword + '\'' + + ", certificateURI='" + certificate.getOrNull() + '\'' + + ", certificatePassword='" + certificatePassword.getOrNull() + '\'' + ", mobileProvisionURI='" + mobileProvisionURI + '\'' + '}'; } diff --git a/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy new file mode 100644 index 00000000..c8b55be6 --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy @@ -0,0 +1,33 @@ +package org.openbakery.util + +import org.apache.commons.io.FilenameUtils +import org.apache.commons.lang.StringUtils +import org.gradle.api.Project + +class FileUtil { + + static File download(Project project, + File toDirectory, + String address) throws IllegalArgumentException { + + if (StringUtils.isEmpty(address)) { + throw new IllegalArgumentException("Cannot download, because no address was given") + } + + if (!toDirectory.exists()) { + toDirectory.mkdirs() + } + + try { + project.ant.get(src: address, + dest: toDirectory.getPath(), + verbose: true) + } catch (Exception ex) { + project.logger.error("cannot download file from the given location: {}", address) + throw ex + } + + File file = new File(toDirectory, FilenameUtils.getName(address)) + return file + } +} diff --git a/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy new file mode 100644 index 00000000..5be5140e --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy @@ -0,0 +1,21 @@ +package org.openbakery.util + +import org.openbakery.xcode.Version + +class SystemUtil { + public static Version getOsVersion() { + Version result = new Version() + String versionString = System.getProperty("os.version") + Scanner scanner = new Scanner(versionString).useDelimiter("\\.") + if (scanner.hasNext()) { + result.major = scanner.nextInt() + } + if (scanner.hasNext()) { + result.minor = scanner.nextInt() + } + if (scanner.hasNext()) { + result.maintenance = scanner.nextInt() + } + return result + } +} diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy index 36e2579d..873ed8d0 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy @@ -3,6 +3,8 @@ package org.openbakery.signing import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.TemporaryFolder import org.openbakery.CommandRunner import org.openbakery.XcodePlugin import org.openbakery.codesign.Security @@ -12,6 +14,9 @@ import spock.lang.Specification class KeychainCreateTaskSpecification extends Specification { + @Rule + final TemporaryFolder tmpDirectory = new TemporaryFolder() + Project project KeychainCreateTask keychainCreateTask @@ -19,12 +24,9 @@ class KeychainCreateTaskSpecification extends Specification { File keychainDestinationFile File certificateFile - File tmpDirectory File loginKeychain def setup() { - tmpDirectory = new File(System.getProperty("java.io.tmpdir"), 'gradle-xcodebuild') - project = ProjectBuilder.builder().build() project.buildDir = new File('build').absoluteFile project.apply plugin: org.openbakery.XcodePlugin From 710ba30f982065f1ec31c947a679735287bd3e86 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 10 May 2018 12:47:04 +0100 Subject: [PATCH 080/121] Refactoring of the keychain creation --- .../signing/KeychainCreateTask.groovy | 6 +- .../org/openbakery/signing/Signing.groovy | 4 +- .../org/openbakery/util/SystemUtil.groovy | 2 +- .../KeychainCreateTaskSpecification.groovy | 201 +++++++++--------- .../org/openbakery/util/SystemUtilTest.groovy | 28 +++ 5 files changed, 131 insertions(+), 110 deletions(-) create mode 100644 plugin/src/test/groovy/org/openbakery/util/SystemUtilTest.groovy diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 4abe24d7..ce62ed5c 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -38,6 +38,8 @@ class KeychainCreateTask extends AbstractKeychainTask { @Input final Property keychainTimeout = project.objects.property(Integer) + static final String KEYCHAIN_DEFAULT_PASSWORD = "This_is_the_default_keychain_password" + private File temporaryCertificateFile KeychainCreateTask() { @@ -90,7 +92,7 @@ class KeychainCreateTask extends AbstractKeychainTask { private void createKeyChainAndImportCertificate() { security.get() .createKeychain(keyChainFile.asFile.getOrNull(), - certificatePassword.get()) + KEYCHAIN_DEFAULT_PASSWORD) security.get() .importCertificate(temporaryCertificateFile, @@ -108,7 +110,7 @@ class KeychainCreateTask extends AbstractKeychainTask { if (systemVersion.minor >= 12) { security.get().setPartitionList(keyChainFile.asFile.get(), - certificatePassword.get()) + KEYCHAIN_DEFAULT_PASSWORD) } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index cc403992..51573b5a 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -27,7 +27,7 @@ class Signing { String identity List mobileProvisionURI = null - String keychainPassword = "This_is_the_default_keychain_password" + String plugin Object entitlementsFile @@ -91,7 +91,7 @@ class Signing { if (!mobileProvision.exists()) { throw new IllegalArgumentException("given mobile provision file does not exist: " + mobileProvision.absolutePath) } - mobileProvisionFile.add(mobileProvision) + mobileProvisionFile.add(This_is_the_default_keychain_passwordmobileProvision) } diff --git a/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy index 5be5140e..642e745a 100644 --- a/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy +++ b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy @@ -3,7 +3,7 @@ package org.openbakery.util import org.openbakery.xcode.Version class SystemUtil { - public static Version getOsVersion() { + static Version getOsVersion() { Version result = new Version() String versionString = System.getProperty("os.version") Scanner scanner = new Scanner(versionString).useDelimiter("\\.") diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy index 873ed8d0..89917280 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy @@ -6,11 +6,13 @@ import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.rules.TemporaryFolder import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.codesign.Security import org.openbakery.xcode.Type -import org.openbakery.xcode.Version import spock.lang.Specification +import spock.lang.Unroll + +import static org.openbakery.signing.KeychainCreateTask.KEYCHAIN_DEFAULT_PASSWORD class KeychainCreateTaskSpecification extends Specification { @@ -25,152 +27,141 @@ class KeychainCreateTaskSpecification extends Specification { File certificateFile File loginKeychain + File folder + XcodeBuildPluginExtension xcodeBuildPluginExtension + Security mockSecurity + + final static String CERTIFICATE_PASSWORD = "password" + final static String FAKE_CERT_CONTENT = "Mocked certificate content" def setup() { project = ProjectBuilder.builder().build() project.buildDir = new File('build').absoluteFile project.apply plugin: org.openbakery.XcodePlugin - keychainCreateTask = project.tasks.findByName('keychainCreate') - keychainCreateTask.commandRunner = commandRunner - keychainCreateTask.security.commandRunner = commandRunner + mockSecurity = Mock(Security) + + keychainCreateTask = project.tasks.findByName('keychainCreate') as KeychainCreateTask + keychainCreateTask.security.set(new Security(commandRunner)) + xcodeBuildPluginExtension = project.extensions.getByType(XcodeBuildPluginExtension) + folder = xcodeBuildPluginExtension.signing + .signingDestinationRoot + .get() + .asFile - certificateFile = File.createTempFile("test", ".cert") - keychainDestinationFile = new File(project.xcodebuild.signing.signingDestinationRoot, certificateFile.getName()) + certificateFile = tmpDirectory.newFile("test.cert") + certificateFile.text = FAKE_CERT_CONTENT - loginKeychain = new File(tmpDirectory, "login.keychain") + keychainDestinationFile = new File(folder, + certificateFile.getName()) + + loginKeychain = tmpDirectory.newFile("login.keychain") FileUtils.writeStringToFile(loginKeychain, "dummy") project.xcodebuild.type = Type.macOS - project.xcodebuild.signing.certificateURI = certificateFile.toURL() - project.xcodebuild.signing.certificatePassword = "password" + project.xcodebuild.signing.certificatePassword = CERTIFICATE_PASSWORD project.xcodebuild.signing.timeout = null - - } - - def cleanup() { - certificateFile.delete() - new File(project.xcodebuild.signing.signingDestinationRoot, certificateFile.getName()).delete() - project.xcodebuild.signing.keychainPathInternal.delete() - FileUtils.deleteDirectory(tmpDirectory) - } - - - def "OSVersion"() { - System.setProperty("os.version", "10.9.0"); - - when: - Version version = keychainCreateTask.getOSVersion() - - then: - version != null; - version.major == 10 - version.minor == 9 - version.maintenance == 0 + keychainCreateTask.security.set(mockSecurity) + mockSecurity.getKeychainList() >> [] } - - def "create with OS X 10.8"() { + @Unroll + def "Mac OS #version - Temporary keychain should be create and certificate URI imported"() { given: - System.setProperty("os.version", "10.8.0") - - Security security = Mock(Security) - keychainCreateTask.security = security - security.getKeychainList() >> [] - - when: - keychainCreateTask.create() - - then: - 1 * security.createKeychain(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") - 1 * security.importCertificate(keychainDestinationFile, "password", project.xcodebuild.signing.keychainPathInternal) - 0 * security.setKeychainList([project.xcodebuild.signing.keychainPathInternal]) - } - - - def mockListKeychains() { - String result = " \""+ loginKeychain.absolutePath + "\""; - commandRunner.runWithResult( ["security", "list-keychains"]) >> result - } - - def "create with OS X 10.9 adds keychain to list"() { - given: - System.setProperty("os.version", "10.9.0") - - Security security = Mock(Security) - keychainCreateTask.security = security - security.getKeychainList() >> [] + System.setProperty("os.version", version) + project.xcodebuild.signing.certificateURI = certificateFile.toURL() when: keychainCreateTask.create() - then: - 1 * security.createKeychain(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") - 1 * security.importCertificate(keychainDestinationFile, "password", project.xcodebuild.signing.keychainPathInternal) - 1 * security.setKeychainList([project.xcodebuild.signing.keychainPathInternal]) + then: "The `setPartitionList` method should be call only for OS version > 10.12" + 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), + KEYCHAIN_DEFAULT_PASSWORD) + + 1 * mockSecurity.importCertificate(keychainDestinationFile, + CERTIFICATE_PASSWORD, + xcodeBuildPluginExtension.signing.keyChainFile.asFile.get()) + + count * mockSecurity.setPartitionList(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), + KEYCHAIN_DEFAULT_PASSWORD) + + where: + version | count + "10.8.0" | 0 + "10.9.0" | 0 + "10.11.0" | 0 + "10.12.0" | 1 + "11.12.0" | 1 + "11.12" | 1 } - - def "cleanup first"() { + @Unroll + def "Mac OS #version - Temporary keychain should be create and certificate File imported"() { given: - Security security = Mock(Security) - keychainCreateTask.security = security - security.getKeychainList() >> [] - File toBeDeleted = new File(project.xcodebuild.signing.signingDestinationRoot, "my.keychain") - FileUtils.writeStringToFile(toBeDeleted, "dummy") - mockListKeychains() + System.setProperty("os.version", version) + project.xcodebuild.signing.certificate = certificateFile when: keychainCreateTask.create() - then: - !toBeDeleted.exists() - - } - - - def "depends on"() { - when: - def dependsOn = keychainCreateTask.getDependsOn() - then: - !dependsOn.contains(XcodePlugin.KEYCHAIN_CLEAN_TASK_NAME) + then: "The `setPartitionList` method should be call only for OS version > 10.12" + 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), + KEYCHAIN_DEFAULT_PASSWORD) + + 1 * mockSecurity.importCertificate(keychainDestinationFile, + CERTIFICATE_PASSWORD, + xcodeBuildPluginExtension.signing.keyChainFile.asFile.get()) + + count * mockSecurity.setPartitionList(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), + KEYCHAIN_DEFAULT_PASSWORD) + + where: + version | count + "10.8.0" | 0 + "10.9.0" | 0 + "10.11.0" | 0 + "10.12.0" | 1 + "11.12.0" | 1 + "11.12" | 1 } - - def "create with macOS 10.12.0 set-key-partition-list"() { + @Unroll + def "The keychain timeout should be called"() { given: - System.setProperty("os.version", "10.12.0") - - Security security = Mock(Security) - keychainCreateTask.security = security - security.getKeychainList() >> [] + xcodeBuildPluginExtension.signing.certificate = certificateFile + if (timeout) + xcodeBuildPluginExtension.signing.timeout.set(timeout) when: keychainCreateTask.create() then: - 1 * security.createKeychain(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") - 1 * security.importCertificate(keychainDestinationFile, "password", project.xcodebuild.signing.keychainPathInternal) - 1 * security.setPartitionList(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") + count * mockSecurity.setTimeout(timeout, + xcodeBuildPluginExtension.signing.keyChainFile.asFile.get()) + + where: + timeout | count + 100 | 1 + 400 | 1 + null | 0 } - - def "create with macOS 10.11.0 NOT set-key-partition-list"() { + def "The temporary keychain file should be present post run"() { given: - System.setProperty("os.version", "10.11.0") + project.xcodebuild.signing.certificate = certificateFile - Security security = Mock(Security) - keychainCreateTask.security = security - security.getKeychainList() >> [] when: keychainCreateTask.create() then: - 1 * security.createKeychain(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") - 1 * security.importCertificate(keychainDestinationFile, "password", project.xcodebuild.signing.keychainPathInternal) - 0 * security.setPartitionList(project.xcodebuild.signing.keychainPathInternal, "This_is_the_default_keychain_password") + File file = xcodeBuildPluginExtension.signing + .signingDestinationRoot + .file(certificateFile.name) + .get() + .asFile + file.exists() + file.text == FAKE_CERT_CONTENT } - } diff --git a/plugin/src/test/groovy/org/openbakery/util/SystemUtilTest.groovy b/plugin/src/test/groovy/org/openbakery/util/SystemUtilTest.groovy new file mode 100644 index 00000000..48287c9d --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/util/SystemUtilTest.groovy @@ -0,0 +1,28 @@ +package org.openbakery.util + +import org.openbakery.xcode.Version +import spock.lang.Specification + +class SystemUtilTest extends Specification { + def "Should properly resolve system version from system property"() { + + setup: + System.setProperty("os.version", systemVersion); + + when: + Version version = SystemUtil.getOsVersion() + + then: + version.major == major + version.minor == minor + version.maintenance == maintenance + + where: + systemVersion | major | minor | maintenance + "0.0" | 0 | 0 | -1 + "10.3" | 10 | 3 | -1 + "10.0.1" | 10 | 0 | 1 + "10.1.1" | 10 | 1 | 1 + "10.8.1" | 10 | 8 | 1 + } +} From a6df6907355c25ebbb46f1ba92a71368b567cb9c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 10 May 2018 15:07:03 +0100 Subject: [PATCH 081/121] Refactor and add unit and functional unit test of the keychain creation task --- .../KeychainCreateTaskFunctionalTest.groovy | 162 ++++++++++++++++++ .../PrepareXcodeArchivingTask.groovy | 3 +- .../groovy/org/openbakery/XcodePlugin.groovy | 5 +- .../packaging/PackageLegacyTask.groovy | 15 +- .../packaging/PackageTaskIosAndTvOS.groovy | 3 +- .../signing/KeychainCreateTask.groovy | 22 ++- .../XcodeTestRunTaskSpecification.groovy | 5 +- .../packaging/PackageTaskSpecification.groovy | 3 +- 8 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy diff --git a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy new file mode 100644 index 00000000..266ba80b --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy @@ -0,0 +1,162 @@ +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 + + @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) } + + 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"() { + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments('tasks') + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.output.contains(KeychainCreateTask.TASK_NAME + + " - " + + KeychainCreateTask.TASK_DESCRIPTION) + } + + def "The task should be skipped if invalid configuration"() { + when: + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(KeychainCreateTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.output.contains("No signing certificate defined, will skip the keychain creation") + result.output.contains("No signing certificate password defined, will skip the keychain creation") + result.task(":" + KeychainCreateTask.TASK_NAME).outcome == TaskOutcome.SKIPPED + } + + def "The task should be skipped if not certificate password is provided"() { + setup: + buildFile << """ + xcodebuild { + signing { + certificate = project.file("$certificate") + } + } + """ + + when: + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(KeychainCreateTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.task(":" + KeychainCreateTask.TASK_NAME).outcome == TaskOutcome.SKIPPED + } + + def "The task should be executed if configuration is valid"() { + setup: + buildFile << """ + xcodebuild { + signing { + certificate = project.file("$certificate") + certificatePassword = "p4ssword" + } + } + """ + + when: + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(KeychainCreateTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.task(":" + KeychainCreateTask.TASK_NAME).outcome == TaskOutcome.SUCCESS + } + + def "The task should automatically delete the temporary keychain file"() { + setup: + buildFile << """ + xcodebuild { + signing { + certificate = project.file("$certificate") + certificatePassword = "p4ssword" + } + } + """ + + when: + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(KeychainCreateTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.task(":" + KeychainCreateTask.TASK_NAME).outcome == TaskOutcome.SUCCESS + + and: "The temporary certificate file should be deleted automatically" + new File(testProjectDir.root, "build/codesign") + .listFiles() + .toList() + .findAll {it.name.endsWith(".p12")} + .empty + + and: "The temporary keychain file should be deleted automatically" + new File(testProjectDir.root, "build/codesign") + .listFiles() + .toList() + .findAll {it.name.endsWith(".keychain")} + .empty + + println result.output + } + + 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/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index c618d477..facfdf2b 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -5,6 +5,7 @@ import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.signing.KeychainCreateTask import org.openbakery.util.PathHelper import java.util.function.Consumer @@ -28,7 +29,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { PrepareXcodeArchivingTask() { super() - dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn(KeychainCreateTask.TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index d5a3e727..4e6ca981 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -99,7 +99,6 @@ class XcodePlugin implements Plugin { public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" public static final String HOCKEYKIT_TASK_NAME = "hockeykit" - public static final String KEYCHAIN_CREATE_TASK_NAME = "keychainCreate" public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' @@ -452,7 +451,7 @@ class XcodePlugin implements Plugin { private void configureTestRunDependencies(Project project) { for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { if (xcodeTestRunTask.runOnDevice()) { - xcodeTestRunTask.dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + xcodeTestRunTask.dependsOn(KeychainCreateTask.TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) } } @@ -516,7 +515,7 @@ class XcodePlugin implements Plugin { } private void configureKeychain(Project project) { - project.tasks.create(KEYCHAIN_CREATE_TASK_NAME, KeychainCreateTask.class) { + project.tasks.create(KeychainCreateTask.TASK_NAME, KeychainCreateTask.class) { it.group = XCODE_GROUP_NAME it.certificateFile.set(xcodeBuildPluginExtension.signing.certificate) it.certificatePassword.set(xcodeBuildPluginExtension.signing.certificatePassword) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy index 2817de2e..a1302fb9 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy @@ -12,6 +12,7 @@ import org.openbakery.CommandRunnerException import org.openbakery.bundle.ApplicationBundle import org.openbakery.codesign.Codesign import org.openbakery.codesign.CodesignParameters +import org.openbakery.signing.KeychainCreateTask import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.XcodePlugin @@ -37,12 +38,12 @@ class PackageLegacyTask extends AbstractDistributeTask { super() setDescription("Signs the app bundle that was created by the build and creates the ipa") dependsOn( - XcodePlugin.KEYCHAIN_CREATE_TASK_NAME, - XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, + KeychainCreateTask.TASK_NAME, + XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, ) finalizedBy( - XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME + XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME ) onlyIf(new Spec() { @@ -90,7 +91,7 @@ class PackageLegacyTask extends AbstractDistributeTask { copy(supportDirectory, applicationFolder.parentFile) } - ApplicationBundle applicationBundle = new ApplicationBundle(applicationPath , project.xcodebuild.type, project.xcodebuild.simulator) + ApplicationBundle applicationBundle = new ApplicationBundle(applicationPath, project.xcodebuild.type, project.xcodebuild.simulator) appBundles = applicationBundle.getBundles() File resourceRules = new File(applicationFolder, applicationBundleName + "/ResourceRules.plist") @@ -164,7 +165,7 @@ class PackageLegacyTask extends AbstractDistributeTask { def removeFrameworkFromExtensions(File bundle) { // appex extensions should not contain extensions - if (FilenameUtils.getExtension(bundle.toString()).equalsIgnoreCase("appex")) { + if (FilenameUtils.getExtension(bundle.toString()).equalsIgnoreCase("appex")) { File frameworksPath = new File(bundle, "Frameworks") if (frameworksPath.exists()) { FileUtils.deleteDirectory(frameworksPath) @@ -186,7 +187,7 @@ class PackageLegacyTask extends AbstractDistributeTask { } - def addSwiftSupport(File payloadPath, String applicationBundleName) { + def addSwiftSupport(File payloadPath, String applicationBundleName) { File frameworksPath = new File(payloadPath, applicationBundleName + "/Frameworks") if (!frameworksPath.exists()) { return null @@ -212,7 +213,7 @@ class PackageLegacyTask extends AbstractDistributeTask { filesToZip << packagePath if (includeSwiftSupport) { - File swiftSupportPath = addSwiftSupport(packagePath, applicationBundleName) + File swiftSupportPath = addSwiftSupport(packagePath, applicationBundleName) if (swiftSupportPath != null) { filesToZip << swiftSupportPath } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index c1655964..e04ed4c3 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -7,6 +7,7 @@ import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper import org.openbakery.xcode.Type @@ -35,7 +36,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { description = DESCRIPTION - dependsOn(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn(KeychainCreateTask.TASK_NAME) dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index ce62ed5c..2f3d8a5d 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -38,13 +38,15 @@ class KeychainCreateTask extends AbstractKeychainTask { @Input final Property keychainTimeout = project.objects.property(Integer) + 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" private File temporaryCertificateFile KeychainCreateTask() { super() - this.description = "Create a keychain that is used for signing the app" + this.description = TASK_DESCRIPTION onlyIf { XcodeBuildPluginExtension extension = project .getExtensions() @@ -52,11 +54,13 @@ class KeychainCreateTask extends AbstractKeychainTask { Signing signing = extension.signing - if (!signing.certificate.present) - logger.warn("Not signing certificate defined, will skip the keychain creation") + if (!signing.certificate.present) { + logger.warn("No signing certificate defined, will skip the keychain creation") + } - if (!signing.certificatePassword.present) - logger.warn("Not signing certificate password defined, will skip the keychain creation") + if (!signing.certificatePassword.present) { + logger.warn("No signing certificate password defined, will skip the keychain creation") + } if (keyChainFile.present && keyChainFile.asFile.get().exists()) { logger.debug("Using keychain : " + keyChainFile.get()) @@ -98,6 +102,13 @@ class KeychainCreateTask extends AbstractKeychainTask { .importCertificate(temporaryCertificateFile, certificatePassword.get(), keyChainFile.asFile.get()) + + // Delete the temporary keychain on completion + project.gradle.buildFinished { + if (keyChainFile.asFile.get()) { + keyChainFile.asFile.get().delete() + } + } } private void addKeyChainToThePartitionList() { @@ -112,7 +123,6 @@ class KeychainCreateTask extends AbstractKeychainTask { security.get().setPartitionList(keyChainFile.asFile.get(), KEYCHAIN_DEFAULT_PASSWORD) } - } private void setupOptionalTimeout() { diff --git a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy index 50a39af2..455256af 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy @@ -6,6 +6,7 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.codesign.Codesign import org.openbakery.output.TestBuildOutputAppender +import org.openbakery.signing.KeychainCreateTask import org.openbakery.test.TestResultParser import org.openbakery.testdouble.SimulatorControlStub import org.openbakery.testdouble.XcodeFake @@ -241,7 +242,7 @@ class XcodeTestRunTaskSpecification extends Specification { project.evaluate() then: - !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME)) + !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(KeychainCreateTask.TASK_NAME)) !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME)) } @@ -267,7 +268,7 @@ class XcodeTestRunTaskSpecification extends Specification { project.evaluate() then: - xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME)) + xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(KeychainCreateTask.TASK_NAME)) xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME)) } diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index bca036b9..382827c9 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -8,6 +8,7 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.XcodePlugin import org.openbakery.output.StyledTextOutputStub +import org.openbakery.signing.KeychainCreateTask import org.openbakery.test.ApplicationDummy import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake @@ -440,7 +441,7 @@ class PackageTaskSpecification extends Specification { when: def dependsOn = packageTask.getDependsOn() then: - dependsOn.contains(XcodePlugin.KEYCHAIN_CREATE_TASK_NAME) + dependsOn.contains(KeychainCreateTask.TASK_NAME) dependsOn.contains(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) } From 551a922ab71aeea80349181c543ebb7fa629313d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 11 May 2018 09:50:23 +0100 Subject: [PATCH 082/121] --wip-- [skip ci] --- plugin/build.gradle | 1 + .../openbakery/AbstractXcodeBuildTask.groovy | 2 +- .../PrepareXcodeArchivingTask.groovy | 3 +- .../groovy/org/openbakery/XcodePlugin.groovy | 15 +- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 4 +- .../XcodeBuildLegacyArchiveTask.groovy | 3 +- .../packaging/PackageLegacyTask.groovy | 3 +- .../packaging/PackageTaskIosAndTvOS.groovy | 3 +- .../signing/KeychainCreateTask.groovy | 15 -- .../signing/ProvisioningInstallTask.groovy | 154 +++++++++++------- .../org/openbakery/signing/Signing.groovy | 46 ++++-- .../XcodeBuildArchiveTaskSpecification.groovy | 3 +- .../XcodeTestRunTaskSpecification.groovy | 5 +- .../packaging/PackageTaskSpecification.groovy | 3 +- ...isioningInstallTaskOSXSpecification.groovy | 3 +- ...rovisioningInstallTaskSpecification.groovy | 4 +- 16 files changed, 155 insertions(+), 112 deletions(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index 8c6245f5..105832cf 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -45,6 +45,7 @@ dependencies { compile 'org.pegdown:pegdown:1.5.+' compile 'org.openbakery.coverage:CoverageReport:0.9.4' deployerJars 'org.apache.maven.wagon:wagon-ssh:2.10' + compile 'de.undercouch:gradle-download-task:3.4.3' } jar { diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 239c887c..904076ef 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -131,7 +131,7 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { } List getProvisioningUriList() { - return getXcodeExtension().signing.mobileProvisionURI + return getXcodeExtension().signing.mobileProvisionURI.get() } String getSignatureFriendlyName() { diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index facfdf2b..559dd34b 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -6,6 +6,7 @@ import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import java.util.function.Consumer @@ -30,7 +31,7 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { super() dependsOn(KeychainCreateTask.TASK_NAME) - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 4e6ca981..385befc5 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -58,6 +58,7 @@ import org.openbakery.packaging.PackageTask import org.openbakery.packaging.PackageTaskIosAndTvOS import org.openbakery.signing.* import org.openbakery.simulators.* +import org.openbakery.util.PlistHelper import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -102,7 +103,6 @@ class XcodePlugin implements Plugin { public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' - public static final String PROVISIONING_INSTALL_TASK_NAME = 'provisioningInstall' public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' @@ -136,6 +136,7 @@ class XcodePlugin implements Plugin { private XcodeBuildPluginExtension xcodeBuildPluginExtension private CommandRunner commandRunner + private PlistHelper plistHelper private Security securityTool void apply(Project project) { @@ -169,6 +170,7 @@ class XcodePlugin implements Plugin { void setupTools(Project project) { this.commandRunner = new CommandRunner() + this.plistHelper = new PlistHelper(commandRunner) this.securityTool = new Security(commandRunner) } @@ -451,7 +453,7 @@ class XcodePlugin implements Plugin { private void configureTestRunDependencies(Project project) { for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { if (xcodeTestRunTask.runOnDevice()) { - xcodeTestRunTask.dependsOn(KeychainCreateTask.TASK_NAME, XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + xcodeTestRunTask.dependsOn(KeychainCreateTask.TASK_NAME, ProvisioningInstallTask.TASK_NAME) xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) } } @@ -541,7 +543,14 @@ class XcodePlugin implements Plugin { } private configureProvisioning(Project project) { - project.task(PROVISIONING_INSTALL_TASK_NAME, type: ProvisioningInstallTask, group: XCODE_GROUP_NAME) + project.tasks.create(ProvisioningInstallTask.TASK_NAME, + ProvisioningInstallTask) { + it.group = XCODE_GROUP_NAME + it.commandRunnerProperty.set(commandRunner) + it.plistHelperProperty.set(plistHelper) + it.mobileProvisiongList.set(xcodeBuildPluginExtension.signing.mobileProvisionURI) + it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) + } project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) } diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 7166ea24..44c001fc 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -6,7 +6,7 @@ import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask import org.openbakery.PrepareXcodeArchivingTask -import org.openbakery.XcodePlugin +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild @@ -20,7 +20,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { XcodeBuildArchiveTaskIosAndTvOS() { super() - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) this.description = "Use the xcodebuild archiver to create the project archive" diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy index 668a7f77..893e1e11 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy @@ -25,6 +25,7 @@ import org.openbakery.BuildConfiguration import org.openbakery.CommandRunnerException import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Extension @@ -40,7 +41,7 @@ class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { super() dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME, - XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + ProvisioningInstallTask.TASK_NAME) this.description = "Use the legacy archiver to create the project archive" diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy index a1302fb9..4c2dbf83 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy @@ -13,6 +13,7 @@ import org.openbakery.bundle.ApplicationBundle import org.openbakery.codesign.Codesign import org.openbakery.codesign.CodesignParameters import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.XcodePlugin @@ -39,7 +40,7 @@ class PackageLegacyTask extends AbstractDistributeTask { setDescription("Signs the app bundle that was created by the build and creates the ipa") dependsOn( KeychainCreateTask.TASK_NAME, - XcodePlugin.PROVISIONING_INSTALL_TASK_NAME, + ProvisioningInstallTask.TASK_NAME ) finalizedBy( diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index e04ed4c3..172dd693 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -8,6 +8,7 @@ import org.openbakery.AbstractXcodeBuildTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper import org.openbakery.xcode.Type @@ -37,7 +38,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { description = DESCRIPTION dependsOn(KeychainCreateTask.TASK_NAME) - dependsOn(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 2f3d8a5d..06633cac 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -1,18 +1,3 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.openbakery.signing import groovy.transform.CompileStatic diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 0474a854..98587143 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -1,87 +1,117 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.openbakery.signing +import de.undercouch.gradle.tasks.download.Download +import groovy.transform.CompileStatic import org.apache.commons.io.FilenameUtils +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction -import org.openbakery.AbstractXcodeTask -import org.openbakery.XcodePlugin +import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.util.FileUtil +import org.openbakery.util.PlistHelper -class ProvisioningInstallTask extends AbstractXcodeTask { - - public final static PROVISIONING_NAME_BASE = "gradle-" +@CompileStatic +class ProvisioningInstallTask extends Download { + @Input + final Provider> mobileProvisiongList = project.objects.listProperty(String) - ProvisioningInstallTask() { - super() - dependsOn(XcodePlugin.PROVISIONING_CLEAN_TASK_NAME) - this.description = "Installs the given provisioning profile" - } + final Property commandRunnerProperty = project.objects.property(CommandRunner) + final Property plistHelperProperty = project.objects.property(PlistHelper) + final DirectoryProperty outputDirectory = newOutputDirectory() - void linkToLibraray(File mobileProvisionFile) { - File provisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); - if (!provisionPath.exists()) { - provisionPath.mkdirs() - } - - File mobileProvisionFileLinkToLibrary = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/" + mobileProvisionFile.getName()); - if (mobileProvisionFileLinkToLibrary.exists()) { - mobileProvisionFileLinkToLibrary.delete() - } + public final static PROVISIONING_NAME_BASE = "gradle-" + static final String TASK_NAME = "provisioningInstall" + static final String TASK_DESCRIPTION = "Installs the given provisioning profile" - commandRunner.run(["/bin/ln", "-s", mobileProvisionFile.absolutePath, mobileProvisionFileLinkToLibrary.absolutePath]) + ProvisioningInstallTask() { + super() + this.description = TASK_DESCRIPTION + this.onlyIf { !mobileProvisiongList.get().empty } } +// +// void linkToLibraray(File mobileProvisionFile) { +// File provisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); +// if (!provisionPath.exists()) { +// provisionPath.mkdirs() +// } +// +// File mobileProvisionFileLinkToLibrary = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/" + mobileProvisionFile.getName()); +// if (mobileProvisionFileLinkToLibrary.exists()) { +// mobileProvisionFileLinkToLibrary.delete() +// } +// +// commandRunner.run(["/bin/ln", "-s", mobileProvisionFile.absolutePath, mobileProvisionFileLinkToLibrary.absolutePath]) +// } @TaskAction - def install() { - - - if (project.xcodebuild.signing.mobileProvisionURI == null) { - logger.lifecycle("No provisioning profile specifed so do nothing here") - return - } - - for (String mobileProvisionURI : project.xcodebuild.signing.mobileProvisionURI) { - def mobileProvisionFile = FileUtil.download(project, - project.xcodebuild.signing.mobileProvisionDestinationRoot, - mobileProvisionURI).absolutePath - - ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(new File(mobileProvisionFile), this.commandRunner, this.plistHelper) - - String uuid = provisioningProfileIdReader.getUUID() + @Override + public void download() throws IOException { + this.src(mobileProvisiongList.get().asList()) + this.dest(outputDirectory.asFile.get()) + this.acceptAnyCertificate(true) + + super.download() + + final List files = rename() + + deleteFilesOnExit(files) + +// +// for (String mobileProvisionURI : project.xcodebuild.signing.mobileProvisionURI) { +// def mobileProvisionFile = FileUtil.download(project, +// project.xcodebuild.signing.mobileProvisionDestinationRoot, +// mobileProvisionURI).absolutePath +// +// ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(new File(mobileProvisionFile), this.commandRunner, this.plistHelper) +// +// String uuid = provisioningProfileIdReader.getUUID() +// +// +// String extension = FilenameUtils.getExtension(mobileProvisionFile) +// String mobileProvisionName +// mobileProvisionName = PROVISIONING_NAME_BASE + uuid + "." + extension +// +// +// File downloadedFile = new File(mobileProvisionFile) +// File renamedProvisionFile = new File(downloadedFile.getParentFile(), mobileProvisionName) +// downloadedFile.renameTo(renamedProvisionFile) +// +// project.xcodebuild.signing.addMobileProvisionFile(renamedProvisionFile) +// +// linkToLibraray(renamedProvisionFile) +// } + } - String extension = FilenameUtils.getExtension(mobileProvisionFile) - String mobileProvisionName - mobileProvisionName = PROVISIONING_NAME_BASE + uuid + "." + extension + private List rename() { + return mobileProvisiongList.get() + .collect { new File(outputDirectory.get().asFile, FilenameUtils.getName(it)) } + .collect { return renameProvisioningFile(it) } + } + private void deleteFilesOnExit(final List files) { + project.gradle.buildFinished { + files.each { it.delete() } + } - File downloadedFile = new File(mobileProvisionFile) - File renamedProvisionFile = new File(downloadedFile.getParentFile(), mobileProvisionName) - downloadedFile.renameTo(renamedProvisionFile) + return files + } - project.xcodebuild.signing.addMobileProvisionFile(renamedProvisionFile) + private File renameProvisioningFile(File file) { + ProvisioningProfileReader reader = new ProvisioningProfileReader(file, + commandRunnerProperty.get(), + plistHelperProperty.get()) - linkToLibraray(renamedProvisionFile) - } + String fileName = reader.getUUID() + "." + FilenameUtils.getExtension(file.getName()) + File result = new File(outputDirectory.get().asFile, fileName) + assert file.renameTo(result): "Failed to rename the provisioning file" + return result } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 51573b5a..ebc2e09b 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -3,6 +3,7 @@ package org.openbakery.signing import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Internal import org.openbakery.CommandRunner @@ -18,6 +19,8 @@ class Signing { final RegularFileProperty certificate final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() + final ListProperty mobileProvisionURI = project.objects.listProperty(String) +// final ConfigurableFileCollection registeredProvisioningFiles = project.files() @Internal Object keychainPathInternal @@ -26,7 +29,7 @@ class Signing { String identity - List mobileProvisionURI = null +// List mobileProvisionURI = null String plugin Object entitlementsFile @@ -37,7 +40,8 @@ class Signing { * internal parameters */ private final Project project - private final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" + private + final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" CommandRunner commandRunner List mobileProvisionFile = new ArrayList() @@ -48,6 +52,7 @@ class Signing { Signing(Project project) { this.project = project this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) + this.signingDestinationRoot.asFile.get().mkdirs() this.certificate = project.layout.fileProperty() this.certificatePassword = project.objects.property(String) this.commandRunner = new CommandRunner() @@ -77,23 +82,32 @@ class Signing { return project.file(keychainPathInternal) } - void setMobileProvisionURI(Object mobileProvisionURI) { - if (mobileProvisionURI instanceof List) { - this.mobileProvisionURI = mobileProvisionURI; - } else { - this.mobileProvisionURI = new ArrayList(); - this.mobileProvisionURI.add(mobileProvisionURI.toString()); - } +// void setMobileProvisionURI(Object mobileProvisionURI) { +// if (mobileProvisionURI instanceof List) { +// this.mobileProvisionURI = mobileProvisionURI; +// } else { +// this.mobileProvisionURI = new ArrayList(); +// this.mobileProvisionURI.add(mobileProvisionURI.toString()); +// } +// } + + @Deprecated + void setMobileProvisionURI(List list) { + list.each { this.mobileProvisionURI.add(it) } } - - void addMobileProvisionFile(File mobileProvision) { - if (!mobileProvision.exists()) { - throw new IllegalArgumentException("given mobile provision file does not exist: " + mobileProvision.absolutePath) - } - mobileProvisionFile.add(This_is_the_default_keychain_passwordmobileProvision) + @Deprecated + void setMobileProvisionURI(String string) { + this.mobileProvisionURI.add(string) } +// void addMobileProvisionFile(File mobileProvision) { +// if (!mobileProvision.exists()) { +// throw new IllegalArgumentException("given mobile provision file does not exist: " + mobileProvision.absolutePath) +// } +// mobileProvisionFile.add(mobileProvision) +// } + File getEntitlementsFile() { if (entitlementsFile != null) { @@ -147,7 +161,7 @@ class Signing { CodesignParameters getCodesignParameters() { CodesignParameters result = new CodesignParameters() result.signingIdentity = getIdentity() - result.mobileProvisionFiles = getMobileProvisionFile().clone() + result.mobileProvisionFiles = mobileProvisionFile.clone() result.keychain = getKeychain() if (entitlements != null) { result.entitlements = entitlements.clone() diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy index 969675f9..76142e4e 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildArchiveTaskSpecification.groovy @@ -6,6 +6,7 @@ import org.apache.commons.lang.RandomStringUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.archiving.XcodeBuildLegacyArchiveTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.SimulatorControlStub import org.openbakery.testdouble.XcodeFake @@ -159,7 +160,7 @@ class XcodeBuildArchiveTaskSpecification extends Specification { dependsOn.size() == 2 dependsOn.contains(XcodePlugin.XCODE_BUILD_TASK_NAME) - dependsOn.contains(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn.contains(ProvisioningInstallTask.TASK_NAME) } diff --git a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy index 455256af..e840ef6e 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy @@ -7,6 +7,7 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.codesign.Codesign import org.openbakery.output.TestBuildOutputAppender import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.test.TestResultParser import org.openbakery.testdouble.SimulatorControlStub import org.openbakery.testdouble.XcodeFake @@ -243,7 +244,7 @@ class XcodeTestRunTaskSpecification extends Specification { then: !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(KeychainCreateTask.TASK_NAME)) - !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME)) + !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(ProvisioningInstallTask.TASK_NAME)) } def "when keychain dependency then also has finalized keychain remove"() { @@ -269,7 +270,7 @@ class XcodeTestRunTaskSpecification extends Specification { then: xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(KeychainCreateTask.TASK_NAME)) - xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME)) + xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(ProvisioningInstallTask.TASK_NAME)) } diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy index 382827c9..bdc7e919 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy @@ -9,6 +9,7 @@ import org.openbakery.CommandRunner import org.openbakery.XcodePlugin import org.openbakery.output.StyledTextOutputStub import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.test.ApplicationDummy import org.openbakery.testdouble.PlistHelperStub import org.openbakery.testdouble.XcodeFake @@ -442,7 +443,7 @@ class PackageTaskSpecification extends Specification { def dependsOn = packageTask.getDependsOn() then: dependsOn.contains(KeychainCreateTask.TASK_NAME) - dependsOn.contains(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + dependsOn.contains(ProvisioningInstallTask.TASK_NAME) } diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy index a7e78359..8a5777aa 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy @@ -6,7 +6,6 @@ import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin import spock.lang.Specification class ProvisioningInstallTaskOSXSpecification extends Specification { @@ -30,7 +29,7 @@ class ProvisioningInstallTaskOSXSpecification extends Specification { project.xcodebuild.type = Type.macOS - provisioningInstallTask = project.getTasks().getByPath(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + provisioningInstallTask = project.getTasks().getByPath(ProvisioningInstallTask.TASK_NAME) provisioningInstallTask.commandRunner = commandRunner diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy index 784ac105..8ed71e2d 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy @@ -5,10 +5,8 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.XcodePlugin import spock.lang.Specification - class ProvisioningInstallTaskSpecification extends Specification { Project project @@ -30,7 +28,7 @@ class ProvisioningInstallTaskSpecification extends Specification { project.xcodebuild.simulator = false - provisioningInstallTask = project.getTasks().getByPath(XcodePlugin.PROVISIONING_INSTALL_TASK_NAME) + provisioningInstallTask = project.getTasks().getByPath(ProvisioningInstallTask.TASK_NAME) provisioningInstallTask.commandRunner = commandRunner From 1e17389e6989fece5c4df27c9ca25e3a3192e1fe Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 11 May 2018 09:51:02 +0100 Subject: [PATCH 083/121] --wip-- [skip ci] --- .../org/openbakery/signing/ProvisioningInstallTask.groovy | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 98587143..ae31bc9c 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -99,8 +99,6 @@ class ProvisioningInstallTask extends Download { project.gradle.buildFinished { files.each { it.delete() } } - - return files } private File renameProvisioningFile(File file) { From 31c8b34c74d89c481e81e3b18a4e61248ee7f296 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 11 May 2018 17:31:30 +0100 Subject: [PATCH 084/121] --wip-- [skip ci] --- .../openbakery/AbstractXcodeBuildTask.groovy | 2 +- .../org/openbakery/InfoPlistModifyTask.groovy | 3 +- .../XcodeBuildPluginExtension.groovy | 14 +- .../groovy/org/openbakery/XcodePlugin.groovy | 35 +++- .../org/openbakery/XcodeTestRunTask.groovy | 2 +- .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 13 +- .../XcodeBuildLegacyArchiveTask.groovy | 11 +- .../hockeyapp/HockeyAppUploadTask.groovy | 23 +-- .../packaging/PackageTaskIosAndTvOS.groovy | 34 ++-- .../signing/ProvisioningInstallTask.groovy | 103 ++++++----- .../org/openbakery/signing/Signing.groovy | 54 ++---- .../InfoPlistModifyTaskSpecification.groovy | 2 +- ...deBuildPluginExtensionSpecification.groovy | 2 +- ...rovisioningInstallTaskSpecification.groovy | 162 ++++++++++-------- 14 files changed, 222 insertions(+), 238 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 904076ef..25424c26 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -131,7 +131,7 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { } List getProvisioningUriList() { - return getXcodeExtension().signing.mobileProvisionURI.get() + return getXcodeExtension().signing.mobileProvisionList.get() } String getSignatureFriendlyName() { diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 71b71d40..be025d33 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -142,7 +142,8 @@ class InfoPlistModifyTask extends AbstractDistributeTask { setValueForPlist(KeyBundleIdentifier, extension.bundleIdentifier) } else { XcodeBuildPluginExtension xcodeExtension = getXcodeExtension() - xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme, xcodeExtension.configuration) + xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme.get(), + xcodeExtension.configuration) .map { it -> it.bundleIdentifier } .ifPresent { it -> setValueForPlist(KeyBundleIdentifier, it) } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 50bc7268..142a44f7 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -32,15 +32,17 @@ class XcodeBuildPluginExtension { public final static KEYCHAIN_NAME_BASE = "gradle-" final Property version + final Property scheme final Signing signing + private static Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) XcodebuildParameters _parameters = new XcodebuildParameters() String infoPlist = null - String scheme = null + String configuration = 'Debug' boolean simulator = true Type type = Type.iOS @@ -87,10 +89,10 @@ class XcodeBuildPluginExtension { public XcodeBuildPluginExtension(Project project) { this.project = project; - - this.signing = project.objects.newInstance(Signing, project) this.version = project.objects.property(String) + this.scheme = project.objects.property(String) + this.signing = project.objects.newInstance(Signing, project) this.variableResolver = new VariableResolver(project) commandRunner = new CommandRunner() @@ -118,9 +120,9 @@ class XcodeBuildPluginExtension { } - Optional getBuildTargetConfiguration(String scheme, + Optional getBuildTargetConfiguration(String schemeName, String configuration) { - return Optional.ofNullable(projectSettings.get(scheme, null)) + return Optional.ofNullable(projectSettings.get(schemeName, null)) .map { it -> it.buildSettings } .map { bs -> (BuildConfiguration) bs.get(configuration) } } @@ -454,7 +456,7 @@ class XcodeBuildPluginExtension { XcodebuildParameters getXcodebuildParameters() { def result = new XcodebuildParameters() - result.scheme = this.scheme + result.scheme = this.scheme.get() result.target = this.target result.simulator = this.simulator result.type = this.type diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 385befc5..49578fd4 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -482,9 +482,11 @@ class XcodePlugin implements Plugin { create(PrepareXcodeArchivingTask.NAME, PrepareXcodeArchivingTask.class) prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) - XcodeBuildArchiveTaskIosAndTvOS archiveTask = project.getTasks(). - create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) - archiveTask.setGroup(XCODE_GROUP_NAME) + project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, + XcodeBuildArchiveTaskIosAndTvOS.class) { + it.setGroup(XCODE_GROUP_NAME) + it.scheme.set(xcodeBuildPluginExtension.scheme) + } XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask = project.getTasks(). create(XcodeBuildLegacyArchiveTask.NAME, XcodeBuildLegacyArchiveTask.class) @@ -528,7 +530,14 @@ class XcodePlugin implements Plugin { } project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) - project.task(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, type: KeychainRemoveFromSearchListTask, group: XCODE_GROUP_NAME) + + project.tasks.create(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, + KeychainRemoveFromSearchListTask.class) { + it.group = XCODE_GROUP_NAME + it.keyChainFile.set(xcodeBuildPluginExtension.signing.keyChainFile) + it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) + it.security.set(securityTool) + } } private void configureTest(Project project) { @@ -547,9 +556,14 @@ class XcodePlugin implements Plugin { ProvisioningInstallTask) { it.group = XCODE_GROUP_NAME it.commandRunnerProperty.set(commandRunner) + it.mobileProvisioningList.set(xcodeBuildPluginExtension.signing.mobileProvisionList) + it.outputDirectory.set(xcodeBuildPluginExtension.signing.provisioningDestinationRoot) it.plistHelperProperty.set(plistHelper) - it.mobileProvisiongList.set(xcodeBuildPluginExtension.signing.mobileProvisionURI) - it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) + + // We use the result of the task to populate the read only value + xcodeBuildPluginExtension.signing + .registeredProvisioningFiles + .set(it.registeredProvisioning) } project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) } @@ -579,9 +593,12 @@ class XcodePlugin implements Plugin { } private void configureModernPackager(Project project) { - project.task(PackageTaskIosAndTvOS.NAME, - type: PackageTaskIosAndTvOS, - group: XCODE_GROUP_NAME) + project.tasks.create(PackageTaskIosAndTvOS.NAME, + PackageTaskIosAndTvOS) { + it.group = XCODE_GROUP_NAME + it.signingMethod.set(xcodeBuildPluginExtension.signing.signingMethod) + it.scheme.set(xcodeBuildPluginExtension.scheme) + } } private void configureLegacyPackager(Project project) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodeTestRunTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeTestRunTask.groovy index 9b601274..91e70770 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeTestRunTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeTestRunTask.groovy @@ -152,7 +152,7 @@ class XcodeTestRunTask extends AbstractXcodeBuildTask { CodesignParameters parameters = new CodesignParameters() parameters.signingIdentity = getSigningIdentity() parameters.keychain = project.xcodebuild.signing.keychainPathInternal - parameters.mobileProvisionFiles = project.xcodebuild.signing.mobileProvisionFile + parameters.mobileProvisionFiles = project.extensions.getByType(XcodeBuildPluginExtension).signing.registeredProvisioningFiles.getFiles().asList() parameters.type = project.xcodebuild.type codesign = new Codesign(xcode, parameters, commandRunner, plistHelper) if (project.xcodebuild.signing.hasEntitlementsFile()) { diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 44c001fc..50c90182 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -2,6 +2,7 @@ package org.openbakery.archiving import groovy.transform.CompileStatic import org.gradle.api.Task +import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask @@ -15,6 +16,9 @@ import org.openbakery.xcode.Xcodebuild @CacheableTask class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { + @Input + final Provider scheme = project.objects.property(String) + public static final String NAME = "archiveXcodeBuild" XcodeBuildArchiveTaskIosAndTvOS() { @@ -39,11 +43,6 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { return PathHelper.resolveXcConfigFile(project) } - @Input - String getScheme() { - return getXcodeExtension().scheme - } - @OutputFile File getOutputTextFile() { return PathHelper.resolveArchivingLogFile(project) @@ -66,8 +65,8 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { commandRunner.setOutputFile(getOutputTextFile()) - xcodeBuild.archive(getScheme(), - PathHelper.resolveArchiveFile(project, scheme), + xcodeBuild.archive(scheme.get(), + PathHelper.resolveArchiveFile(project, scheme.get()), getXcConfigFile()) } } diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy index 893e1e11..b21f043b 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy @@ -23,12 +23,13 @@ import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeBuildTask import org.openbakery.BuildConfiguration import org.openbakery.CommandRunnerException +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper -import org.openbakery.xcode.Type import org.openbakery.xcode.Extension +import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild import static groovy.io.FileType.FILES @@ -322,8 +323,12 @@ class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { } String applicationIdentifier = "UNKNOWN00ID"; + // if UNKNOWN00ID this means that not application identifier is found an this value is used as fallback - File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, project.xcodebuild.signing.mobileProvisionFile, this.commandRunner, this.plistHelper) + File provisioningProfile = ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, + project.extensions.getByType(XcodeBuildPluginExtension).signing.registeredProvisioningFiles.getFiles().asList(), + this.commandRunner, + this.plistHelper) if (provisioningProfile != null && provisioningProfile.exists()) { ProvisioningProfileReader reader = new ProvisioningProfileReader(provisioningProfile, commandRunner) applicationIdentifier = reader.getApplicationIdentifierPrefix() @@ -530,7 +535,7 @@ class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { File getArchiveDirectory() { - def archiveDirectoryName = PathHelper.FOLDER_ARCHIVE + "/" + project.xcodebuild.bundleName + def archiveDirectoryName = PathHelper.FOLDER_ARCHIVE + "/" + project.xcodebuild.bundleName if (project.xcodebuild.bundleNameSuffix != null) { archiveDirectoryName += project.xcodebuild.bundleNameSuffix diff --git a/plugin/src/main/groovy/org/openbakery/hockeyapp/HockeyAppUploadTask.groovy b/plugin/src/main/groovy/org/openbakery/hockeyapp/HockeyAppUploadTask.groovy index 6b9a887e..e15723d7 100644 --- a/plugin/src/main/groovy/org/openbakery/hockeyapp/HockeyAppUploadTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/hockeyapp/HockeyAppUploadTask.groovy @@ -15,31 +15,12 @@ */ package org.openbakery.hockeyapp -import org.apache.commons.io.FilenameUtils import org.apache.http.Consts -import org.apache.http.HttpEntity -import org.apache.http.HttpHost -import org.apache.http.HttpResponse -import org.apache.http.client.HttpClient -import org.apache.http.client.config.RequestConfig -import org.apache.http.client.methods.CloseableHttpResponse -import org.apache.http.client.methods.HttpPost import org.apache.http.entity.ContentType -import org.apache.http.entity.mime.MultipartEntity -import org.apache.http.entity.mime.MultipartEntityBuilder -import org.apache.http.entity.mime.content.FileBody -import org.apache.http.entity.mime.content.StringBody -import org.apache.http.impl.client.CloseableHttpClient -import org.apache.http.impl.client.DefaultHttpClient -import org.apache.http.impl.client.HttpClients -import org.apache.http.util.EntityUtils -import org.gradle.api.DefaultTask import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractDistributeTask import org.openbakery.http.HttpUpload -import java.util.regex.Pattern - class HockeyAppUploadTask extends AbstractDistributeTask { @@ -130,7 +111,7 @@ class HockeyAppUploadTask extends AbstractDistributeTask { httpUpload.url = HOCKEY_APP_API_URL + project.hockeyapp.appID + "/provisioning_profiles" - if (project.xcodebuild.signing.mobileProvisionFile.size() != 1) { + if (project.xcodebuild.signing.registeredProvisioningFiles.get().size() != 1) { logger.debug("mobileProvisionFile not found"); return; } @@ -141,7 +122,7 @@ class HockeyAppUploadTask extends AbstractDistributeTask { } httpUpload.postRequest(getHttpHeaders(), - ["mobileprovision": project.xcodebuild.signing.mobileProvisionFile.get(0)] + ["mobileprovision": project.xcodebuild.signing.registeredProvisioningFiles.get().get(0)] ) } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 172dd693..406692fc 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -2,6 +2,8 @@ package org.openbakery.packaging import groovy.transform.CompileStatic import org.gradle.api.Task +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeBuildTask @@ -14,14 +16,21 @@ import org.openbakery.util.PathHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild -import java.util.Optional - @CompileStatic class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { + @Input + public final Property signingMethod = project.objects.property(SigningMethod) + + @Input + final Provider scheme = project.objects.property(String) + +// @Input +// public final Provider targetType = project.objects.property(Type) + private ProvisioningProfileReader reader - public static final String DESCRIPTION = "Package the IPA from the generate archive by using Xcodebuild" + public static final String DESCRIPTION = "Package the archive with Xcode-build" public static final String NAME = "packageWithXcodeBuild" private static final String PLIST_KEY_METHOD = "method" @@ -43,7 +52,6 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { @@ -61,7 +69,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input boolean getBitCode() { boolean result = getXcodeExtension().bitcode - SigningMethod method = getMethod() + SigningMethod method = signingMethod.get() if (method == SigningMethod.AppStore && getXcodeExtension().type == Type.tvOS) { @@ -86,18 +94,6 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { return super.getSignatureFriendlyName() } - @Input - SigningMethod getMethod() { - return Optional.ofNullable(getXcodeExtension().getSigning().method) - .orElseThrow { new IllegalArgumentException("Invalid signing method") } - } - - @Input - String getScheme() { - return Optional.ofNullable(getXcodeExtension().scheme) - .orElseThrow { new IllegalArgumentException("Invalid scheme") } - } - @Input Map getProvisioningMap() { setupProvisioningProfileReader() @@ -109,7 +105,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @InputDirectory File getArchiveFile() { - return PathHelper.resolveArchiveFile(project, scheme) + return PathHelper.resolveArchiveFile(project, scheme.get()) } @OutputDirectory @@ -145,7 +141,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { // Signing method addStringValueForPlist(PLIST_KEY_METHOD, - getMethod().value) + signingMethod.get().value) // Provisioning profiles map list plistHelper.addDictForPlist(file, diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index ae31bc9c..af0a656b 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -2,11 +2,14 @@ package org.openbakery.signing import de.undercouch.gradle.tasks.download.Download import groovy.transform.CompileStatic +import org.apache.commons.io.FileUtils import org.apache.commons.io.FilenameUtils -import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.Directory +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputFiles import org.gradle.api.tasks.TaskAction import org.openbakery.CommandRunner import org.openbakery.codesign.ProvisioningProfileReader @@ -16,100 +19,90 @@ import org.openbakery.util.PlistHelper class ProvisioningInstallTask extends Download { @Input - final Provider> mobileProvisiongList = project.objects.listProperty(String) + final Provider> mobileProvisioningList = project.objects.listProperty(String) + + @OutputFiles + final ListProperty registeredProvisioning = project.objects.listProperty(File) final Property commandRunnerProperty = project.objects.property(CommandRunner) final Property plistHelperProperty = project.objects.property(PlistHelper) + final Provider outputDirectory = project.layout.directoryProperty() - final DirectoryProperty outputDirectory = newOutputDirectory() - - public final static PROVISIONING_NAME_BASE = "gradle-" + public static final String PROVISIONING_NAME_BASE = "gradle-" + public static final String TASK_NAME = "provisioningInstall" + public static final String TASK_DESCRIPTION = "Installs the given provisioning profile" - static final String TASK_NAME = "provisioningInstall" - static final String TASK_DESCRIPTION = "Installs the given provisioning profile" + static final File PROVISIONING_DIR = new File(System.getProperty("user.home") + + "/Library/MobileDevice/Provisioning Profiles/") ProvisioningInstallTask() { super() this.description = TASK_DESCRIPTION - this.onlyIf { !mobileProvisiongList.get().empty } + this.onlyIf { !mobileProvisioningList.get().empty } } -// -// void linkToLibraray(File mobileProvisionFile) { -// File provisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); -// if (!provisionPath.exists()) { -// provisionPath.mkdirs() -// } -// -// File mobileProvisionFileLinkToLibrary = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/" + mobileProvisionFile.getName()); -// if (mobileProvisionFileLinkToLibrary.exists()) { -// mobileProvisionFileLinkToLibrary.delete() -// } -// -// commandRunner.run(["/bin/ln", "-s", mobileProvisionFile.absolutePath, mobileProvisionFileLinkToLibrary.absolutePath]) -// } @TaskAction @Override - public void download() throws IOException { - this.src(mobileProvisiongList.get().asList()) - this.dest(outputDirectory.asFile.get()) - this.acceptAnyCertificate(true) - + void download() throws IOException { + outputDirectory.get().asFile.mkdirs() + configureDownload() super.download() + postDownload() + } - final List files = rename() + private void configureDownload() { + this.src(mobileProvisioningList.get().asList()) + this.dest(outputDirectory.get().asFile) + this.acceptAnyCertificate(true) + } + private void postDownload() { + final List files = rename() deleteFilesOnExit(files) -// -// for (String mobileProvisionURI : project.xcodebuild.signing.mobileProvisionURI) { -// def mobileProvisionFile = FileUtil.download(project, -// project.xcodebuild.signing.mobileProvisionDestinationRoot, -// mobileProvisionURI).absolutePath -// -// ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(new File(mobileProvisionFile), this.commandRunner, this.plistHelper) -// -// String uuid = provisioningProfileIdReader.getUUID() -// -// -// String extension = FilenameUtils.getExtension(mobileProvisionFile) -// String mobileProvisionName -// mobileProvisionName = PROVISIONING_NAME_BASE + uuid + "." + extension -// -// -// File downloadedFile = new File(mobileProvisionFile) -// File renamedProvisionFile = new File(downloadedFile.getParentFile(), mobileProvisionName) -// downloadedFile.renameTo(renamedProvisionFile) -// -// project.xcodebuild.signing.addMobileProvisionFile(renamedProvisionFile) -// -// linkToLibraray(renamedProvisionFile) -// } + final List libraryFiles = files.each { registeredProvisioning.add(it) } + .collect { linkToUserlibraryOfProvisioning(it) } + deleteFilesOnExit(libraryFiles) } private List rename() { - return mobileProvisiongList.get() + return mobileProvisioningList.get() .collect { new File(outputDirectory.get().asFile, FilenameUtils.getName(it)) } .collect { return renameProvisioningFile(it) } } private void deleteFilesOnExit(final List files) { project.gradle.buildFinished { - files.each { it.delete() } + files.each { + logger.debug("Delete file : " + it.absolutePath) + it.delete() + } } } private File renameProvisioningFile(File file) { + assert file.exists(): "Cannot rename a non existing file" + ProvisioningProfileReader reader = new ProvisioningProfileReader(file, commandRunnerProperty.get(), plistHelperProperty.get()) - String fileName = reader.getUUID() + "." + FilenameUtils.getExtension(file.getName()) + String fileName = PROVISIONING_NAME_BASE + reader.getUUID() + "." + FilenameUtils.getExtension(file.getName()) File result = new File(outputDirectory.get().asFile, fileName) assert file.renameTo(result): "Failed to rename the provisioning file" return result } + + private File linkToUserlibraryOfProvisioning(File file) { + if (!PROVISIONING_DIR.exists()) { + PROVISIONING_DIR.mkdirs() + } + + File destinationFile = new File(PROVISIONING_DIR, file.name) + FileUtils.copyFile(file, destinationFile) + return destinationFile + } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index ebc2e09b..2f9c2328 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -5,6 +5,7 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Internal import org.openbakery.CommandRunner import org.openbakery.codesign.CodesignParameters @@ -14,13 +15,17 @@ import javax.inject.Inject class Signing { final DirectoryProperty signingDestinationRoot = project.layout.directoryProperty() + final DirectoryProperty provisioningDestinationRoot = project.layout.directoryProperty() final Property certificatePassword final Property timeout = project.objects.property(Integer) + final Property signingMethod = project.objects.property(SigningMethod) final RegularFileProperty certificate final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() - final ListProperty mobileProvisionURI = project.objects.listProperty(String) -// final ConfigurableFileCollection registeredProvisioningFiles = project.files() + final ListProperty mobileProvisionList = project.objects.listProperty(String) + + @Internal + final Provider> registeredProvisioningFiles = project.objects.listProperty(File) @Internal Object keychainPathInternal @@ -29,8 +34,6 @@ class Signing { String identity -// List mobileProvisionURI = null - String plugin Object entitlementsFile @@ -46,13 +49,11 @@ class Signing { List mobileProvisionFile = new ArrayList() - private SigningMethod method - @Inject Signing(Project project) { this.project = project this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) - this.signingDestinationRoot.asFile.get().mkdirs() + this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) this.certificate = project.layout.fileProperty() this.certificatePassword = project.objects.property(String) this.commandRunner = new CommandRunner() @@ -68,47 +69,24 @@ class Signing { } public void setMethod(String method) { - this.method = SigningMethod.fromString(method) + signingMethod.set(SigningMethod.fromString(method) .orElseThrow { new IllegalArgumentException("Method : $method is not a valid export method") - } - } - - SigningMethod getMethod() { - return method + }) } File getKeychainPathInternal() { return project.file(keychainPathInternal) } -// void setMobileProvisionURI(Object mobileProvisionURI) { -// if (mobileProvisionURI instanceof List) { -// this.mobileProvisionURI = mobileProvisionURI; -// } else { -// this.mobileProvisionURI = new ArrayList(); -// this.mobileProvisionURI.add(mobileProvisionURI.toString()); -// } -// } - - @Deprecated void setMobileProvisionURI(List list) { - list.each { this.mobileProvisionURI.add(it) } + list.each { this.mobileProvisionList.add(it) } } - @Deprecated - void setMobileProvisionURI(String string) { - this.mobileProvisionURI.add(string) + void setMobileProvisionURI(String value) { + this.mobileProvisionList.add(value) } -// void addMobileProvisionFile(File mobileProvision) { -// if (!mobileProvision.exists()) { -// throw new IllegalArgumentException("given mobile provision file does not exist: " + mobileProvision.absolutePath) -// } -// mobileProvisionFile.add(mobileProvision) -// } - - File getEntitlementsFile() { if (entitlementsFile != null) { if (entitlementsFile instanceof File) { @@ -146,7 +124,7 @@ class Signing { if (this.keychain != null) { return "Signing{" + " identity='" + identity + '\'' + - ", mobileProvisionURI='" + mobileProvisionURI + '\'' + + ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + ", keychain='" + keychain + '\'' + '}'; } @@ -154,14 +132,14 @@ class Signing { " identity='" + identity + '\'' + ", certificateURI='" + certificate.getOrNull() + '\'' + ", certificatePassword='" + certificatePassword.getOrNull() + '\'' + - ", mobileProvisionURI='" + mobileProvisionURI + '\'' + + ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + '}'; } CodesignParameters getCodesignParameters() { CodesignParameters result = new CodesignParameters() result.signingIdentity = getIdentity() - result.mobileProvisionFiles = mobileProvisionFile.clone() + result.mobileProvisionFiles = registeredProvisioningFiles.getFiles().asList().clone() as List result.keychain = getKeychain() if (entitlements != null) { result.entitlements = entitlements.clone() diff --git a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy index 8fa42990..51f89c58 100644 --- a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy @@ -70,7 +70,7 @@ class InfoPlistModifyTaskSpecification extends Specification { def extension = project.extensions.getByType(XcodeBuildPluginExtension) extension.projectSettings = projectSettings - extension.scheme = scheme + extension.scheme.set(scheme) extension.configuration = configuration project.infoplist.bundleIdentifierSuffix = suffix diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy index ae36f058..2b09d4dc 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy @@ -513,7 +513,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { extension.type = Type.macOS extension.simulator = false extension.target = "ExampleOSX" - extension.scheme = "ExampleScheme" + extension.scheme.set("ExampleScheme") extension.workspace = "workspace" extension.configuration = "configuration" diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy index 8ed71e2d..946c0497 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy @@ -1,128 +1,140 @@ package org.openbakery.signing -import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.TemporaryFolder import org.openbakery.CommandRunner +import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import spock.lang.Specification class ProvisioningInstallTaskSpecification extends Specification { - Project project - ProvisioningInstallTask provisioningInstallTask; + @Rule + final TemporaryFolder tmpDirectory = new TemporaryFolder() + File testMobileProvision1 + File testMobileProvision2 + Project project + ProvisioningInstallTask subject CommandRunner commandRunner = Mock(CommandRunner) - File provisionLibraryPath - File projectDir - - def setup() { + project = ProjectBuilder.builder().withProjectDir(tmpDirectory.root).build() + project.apply plugin: XcodePlugin - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") - - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin - - project.xcodebuild.simulator = false - - provisioningInstallTask = project.getTasks().getByPath(ProvisioningInstallTask.TASK_NAME) + subject = project.tasks.findByName(ProvisioningInstallTask.TASK_NAME) as ProvisioningInstallTask - provisioningInstallTask.commandRunner = commandRunner - - provisionLibraryPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); + testMobileProvision1 = new File("../libtest/src/main/Resource/test.mobileprovision") + testMobileProvision2 = new File("src/test/Resource/test1.mobileprovision") + assert subject != null + assert testMobileProvision1.exists() + assert testMobileProvision2.exists() } - def cleanup() { - FileUtils.deleteDirectory(projectDir) - } + private String formatProvisionFileName(File file) { + assert file.exists() + ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(file, commandRunner) + String uuid = provisioningProfileIdReader.getUUID() + String name = "gradle-" + uuid + ".mobileprovision" - def "single ProvisioningProfile"() { + return name + } - File testMobileprovision = new File("../libtest/src/main/Resource/test.mobileprovision") - project.xcodebuild.signing.mobileProvisionURI = testMobileprovision.toURI().toString() + def "Should process without error a single provisioning file"() { + setup: + project.xcodebuild.signing.mobileProvisionURI = testMobileProvision2.toURI().toString() - ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(testMobileprovision, commandRunner) - String uuid = provisioningProfileIdReader.getUUID() - String name = "gradle-" + uuid + ".mobileprovision"; + project.extensions.getByType(XcodeBuildPluginExtension) + .signing + .mobileProvisionList - File source = new File(projectDir, "build/provision/" + name) - File destination = new File(provisionLibraryPath, name) + String name2 = formatProvisionFileName(testMobileProvision2) - File sourceFile = new File(projectDir, "build/provision/" + name) + File downloadedFile2 = new File(tmpDirectory.root, "build/provision/" + name2) + File libraryFile2 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name2) when: - provisioningInstallTask.install() + subject.download() then: - sourceFile.exists() - 1 * commandRunner.run(["/bin/ln", "-s", source.absolutePath , destination.absolutePath]) + noExceptionThrown() - } + and: + downloadedFile2.text == testMobileProvision2.text + downloadedFile2.exists() - def "multiple ProvisioningProfiles"() { - - File firstMobileprovision = new File("../libtest/src/main/Resource/test.mobileprovision") - File secondMobileprovision = new File("src/test/Resource/test1.mobileprovision") - project.xcodebuild.signing.mobileProvisionURI = [firstMobileprovision.toURI().toString(), secondMobileprovision.toURI().toString() ] + libraryFile2.text == testMobileProvision2.text + libraryFile2.exists() + } - String firstName = "gradle-" + new ProvisioningProfileReader(firstMobileprovision, new CommandRunner()).getUUID() + ".mobileprovision"; - String secondName = "gradle-" + new ProvisioningProfileReader(secondMobileprovision, new CommandRunner()).getUUID() + ".mobileprovision"; + def "Should process without error a change of build folder"() { + setup: + String alternateBuildFolderName = "alternativeBuildFolder" + project.buildDir = tmpDirectory.newFolder(alternateBuildFolderName) + project.xcodebuild.signing.mobileProvisionURI = testMobileProvision2.toURI().toString() - File firstSource = new File(projectDir, "build/provision/" + firstName) - File firstDestination = new File(provisionLibraryPath, firstName) + project.extensions.getByType(XcodeBuildPluginExtension) + .signing + .mobileProvisionList - File secondSource = new File(projectDir, "build/provision/" + secondName) - File secondDestination = new File(provisionLibraryPath, secondName) + String name2 = formatProvisionFileName(testMobileProvision2) - File firstFile = new File(projectDir, "build/provision/" + firstName) - File secondFile = new File(projectDir, "build/provision/" + secondName) + File downloadedFile2 = new File(tmpDirectory.root, "${alternateBuildFolderName}/provision/" + name2) + File libraryFile2 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name2) when: - provisioningInstallTask.install() - + subject.download() then: - firstFile.exists() - secondFile.exists() - 1 * commandRunner.run(["/bin/ln", "-s", firstSource.absolutePath, firstDestination.absolutePath]) - 1 * commandRunner.run(["/bin/ln", "-s", secondSource.absolutePath, secondDestination.absolutePath]) + noExceptionThrown() + + and: + downloadedFile2.text == testMobileProvision2.text + downloadedFile2.exists() + + libraryFile2.text == testMobileProvision2.text + libraryFile2.exists() } + def "Should process without error multiple provisioning files"() { - def "mobileProvisionFile has mobileprovision extension"() { - given: - File testMobileprovision = new File("../libtest/src/main/Resource/test.mobileprovision") - project.xcodebuild.signing.mobileProvisionURI = testMobileprovision.toURI().toString() + setup: + project.xcodebuild.signing.mobileProvisionURI = [testMobileProvision1, + testMobileProvision2] + .collect { it.toURI().toString() } - ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(testMobileprovision, commandRunner) - String uuid = provisioningProfileIdReader.getUUID() + String name1 = formatProvisionFileName(testMobileProvision1) + String name2 = formatProvisionFileName(testMobileProvision2) + + File downloadedFile1 = new File(tmpDirectory.root, "build/provision/" + name1) + File libraryFile1 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name1) + + File downloadedFile2 = new File(tmpDirectory.root, "build/provision/" + name2) + File libraryFile2 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name2) when: - provisioningInstallTask.install() + subject.download() then: - project.xcodebuild.signing.mobileProvisionFile.size == 1 - project.xcodebuild.signing.mobileProvisionFile[0].toString().endsWith(uuid + ".mobileprovision") - } + noExceptionThrown() - def "has provisionprofile extension"() { - given: - File testMobileprovision = new File("../plugin/src/test/Resource/test-wildcard-mac.provisionprofile") - project.xcodebuild.signing.mobileProvisionURI = testMobileprovision.toURI().toString() + and: + downloadedFile1.text == testMobileProvision1.text + downloadedFile1.exists() - ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(testMobileprovision, commandRunner) - String uuid = provisioningProfileIdReader.getUUID() + libraryFile1.text == testMobileProvision1.text + libraryFile1.exists() - when: - provisioningInstallTask.install() + and: + downloadedFile2.text == testMobileProvision2.text + downloadedFile2.exists() - then: - project.xcodebuild.signing.mobileProvisionFile.size == 1 - project.xcodebuild.signing.mobileProvisionFile[0].toString().endsWith(uuid + ".provisionprofile") + libraryFile2.text == testMobileProvision2.text + libraryFile2.exists() } } From 16bacc177973ea0ce1937156feb08be8d9c4af90 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 14 May 2018 10:36:27 +0100 Subject: [PATCH 085/121] --wip-- [skip ci] --- .../org/openbakery/InfoPlistExtension.groovy | 29 +++-- .../org/openbakery/InfoPlistModifyTask.groovy | 5 + .../PrepareXcodeArchivingTask.groovy | 108 +++++++++++------- .../groovy/org/openbakery/XcodePlugin.groovy | 31 ++++- .../org/openbakery/signing/Signing.groovy | 70 ++++++++---- 5 files changed, 168 insertions(+), 75 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy index 2f23eb47..17d237de 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistExtension.groovy @@ -15,6 +15,9 @@ */ package org.openbakery +import org.gradle.api.Project +import org.gradle.api.provider.Property + class InfoPlistExtension { String bundleIdentifier = null String bundleIdentifierSuffix = null @@ -29,7 +32,11 @@ class InfoPlistExtension { String shortVersionStringPrefix = null List commands = null + final Property configurationBundleIdentifier + InfoPlistExtension(Project project) { + this.configurationBundleIdentifier = project.objects.property(String) + } void setCommands(Object commands) { if (commands instanceof List) { @@ -42,16 +49,16 @@ class InfoPlistExtension { boolean hasValuesToModify() { return bundleIdentifier != null || - bundleIdentifierSuffix != null || - bundleName != null || - bundleDisplayName != null || - bundleDisplayNameSuffix != null || - version != null || - versionSuffix != null || - versionPrefix != null || - shortVersionString != null || - shortVersionStringSuffix != null || - shortVersionStringPrefix != null || - commands != null; + bundleIdentifierSuffix != null || + bundleName != null || + bundleDisplayName != null || + bundleDisplayNameSuffix != null || + version != null || + versionSuffix != null || + versionPrefix != null || + shortVersionString != null || + shortVersionStringSuffix != null || + shortVersionStringPrefix != null || + commands != null; } } diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index be025d33..57523198 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -15,6 +15,7 @@ */ package org.openbakery +import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskAction class InfoPlistModifyTask extends AbstractDistributeTask { @@ -22,6 +23,8 @@ class InfoPlistModifyTask extends AbstractDistributeTask { File infoPlist Boolean modfied = false + public final Provider configurationBundleIdentifier = project.objects.property(String) + public static final String KeyBundleIdentifier = "CFBundleIdentifier" public InfoPlistModifyTask() { @@ -78,6 +81,8 @@ class InfoPlistModifyTask extends AbstractDistributeTask { } else { logger.debug("Nothing was modified!") } + + configurationBundleIdentifier.set(getBundleIdentifier()) } private void modifyVersion(File infoPlist) { diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 559dd34b..b44e8123 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -1,21 +1,42 @@ package org.openbakery import groovy.transform.CompileStatic -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction +import org.gradle.api.DefaultTask +import org.gradle.api.Transformer +import org.gradle.api.file.RegularFile +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.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask -import org.openbakery.util.PathHelper - -import java.util.function.Consumer +import org.openbakery.util.PlistHelper @CompileStatic -class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { +class PrepareXcodeArchivingTask extends DefaultTask { + + @InputFile + @Optional + final Provider entitlementsFile = newInputFile() + + @OutputFile + final Provider outputFile = newOutputFile() + + final Property commandRunnerProperty = project.objects.property(CommandRunner) + final Property plistHelperProperty = project.objects.property(PlistHelper) + final ListProperty registeredProvisioningFiles = project.objects.listProperty(File) + final Property configurationBundleIdentifier = project.objects.property(String) + final Property certificateFriendlyName = project.objects.property(String) + + @Internal + private Property entitlementsFilePath = project.objects.property(String) - private ProvisioningProfileReader reader - private final File outputFile + @Internal + final Property provisioningForConfiguration = project.objects.property(File) + + @Internal + final Property provisioningReader = project.objects.property(ProvisioningProfileReader) public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" @@ -36,46 +57,55 @@ class PrepareXcodeArchivingTask extends AbstractXcodeBuildTask { dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) this.description = DESCRIPTION - this.outputFile = PathHelper.resolveXcConfigFile(project) - } - @Input - @Override - List getProvisioningUriList() { - return super.getProvisioningUriList() - } + this.entitlementsFilePath.set(entitlementsFile.map(new Transformer() { + @Override + String transform(RegularFile regularFile) { + return regularFile.asFile.absolutePath + } + })) - @OutputFile - File getXcConfigFile() { - return outputFile + this.provisioningForConfiguration.set(configurationBundleIdentifier.map(new Transformer() { + @Override + File transform(String bundleIdentifier) { + return ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, + registeredProvisioningFiles.get().asList() as List, + commandRunnerProperty.get(), + plistHelperProperty.get()) + } + })) + + this.provisioningReader.set(provisioningForConfiguration.map(new Transformer() { + @Override + ProvisioningProfileReader transform(File file) { + return new ProvisioningProfileReader(file, + commandRunnerProperty.get()) + } + })) } @TaskAction void generate() { - getXcConfigFile().text = "" - computeProvisioningFile() - } + outputFile.get().asFile.text = "" - private void computeProvisioningFile() { - reader = new ProvisioningProfileReader(getProvisioningFile(), commandRunner) - append(KEY_BUNDLE_IDENTIFIER, reader.getApplicationIdentifier()) - append(KEY_CODE_SIGN_IDENTITY, getSignatureFriendlyName()) - append(KEY_DEVELOPMENT_TEAM, reader.getTeamIdentifierPrefix()) - append(KEY_PROVISIONING_PROFILE_ID, reader.getUUID()) - append(KEY_PROVISIONING_PROFILE_SPEC, reader.getName()) - - Optional.ofNullable(getXcodeExtension().signing.entitlementsFile) - .filter { File file -> file.exists() } - .ifPresent(new Consumer() { - @Override - void accept(File file) { - append(KEY_CODE_SIGN_ENTITLEMENTS, file.absolutePath) - } - }) + append(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) + append(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()) + } + + if (entitlementsFilePath.present) { + append(KEY_CODE_SIGN_ENTITLEMENTS, entitlementsFilePath.get()) + } } private void append(String key, String value) { - getXcConfigFile() + outputFile.get() + .asFile .append(System.getProperty("line.separator") + key + " = " + value) } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 49578fd4..ab815ea2 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -134,6 +134,7 @@ class XcodePlugin implements Plugin { private XcodeBuildPluginExtension xcodeBuildPluginExtension + private InfoPlistExtension infoPlistExtension private CommandRunner commandRunner private PlistHelper plistHelper @@ -439,7 +440,10 @@ class XcodePlugin implements Plugin { XcodeBuildPluginExtension, project) - project.extensions.create("infoplist", InfoPlistExtension) + infoPlistExtension = project.extensions.create("infoplist", + InfoPlistExtension, + project) + project.extensions.create("hockeykit", HockeyKitPluginExtension, project) project.extensions.create("appstore", AppstorePluginExtension, project) project.extensions.create("hockeyapp", HockeyAppPluginExtension, project) @@ -478,9 +482,20 @@ class XcodePlugin implements Plugin { } private void configureArchive(Project project) { - PrepareXcodeArchivingTask prepareXcodeArchivingTask = project.getTasks(). - create(PrepareXcodeArchivingTask.NAME, PrepareXcodeArchivingTask.class) - prepareXcodeArchivingTask.setGroup(XCODE_GROUP_NAME) + + project.getTasks() + .create(PrepareXcodeArchivingTask.NAME, + PrepareXcodeArchivingTask.class) { + it.group = XCODE_GROUP_NAME + + it.certificateFriendlyName.set(xcodeBuildPluginExtension.signing.certificateFriendlyName) + it.commandRunnerProperty.set(commandRunner) + it.configurationBundleIdentifier.set(infoPlistExtension.configurationBundleIdentifier) + it.entitlementsFile.set(xcodeBuildPluginExtension.signing.entitlementsFile) + it.outputFile.set(xcodeBuildPluginExtension.signing.xcConfigFile) + it.plistHelperProperty.set(plistHelper) + it.registeredProvisioningFiles.set(xcodeBuildPluginExtension.signing.registeredProvisioningFiles) + } project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) { @@ -548,17 +563,23 @@ class XcodePlugin implements Plugin { } private configureInfoPlist(Project project) { - project.task(INFOPLIST_MODIFY_TASK_NAME, type: InfoPlistModifyTask, group: XCODE_GROUP_NAME) + project.tasks.create(INFOPLIST_MODIFY_TASK_NAME, + InfoPlistModifyTask) { + it.group = XCODE_GROUP_NAME + infoPlistExtension.configurationBundleIdentifier.set(it.configurationBundleIdentifier) + } } private configureProvisioning(Project project) { project.tasks.create(ProvisioningInstallTask.TASK_NAME, ProvisioningInstallTask) { it.group = XCODE_GROUP_NAME + it.commandRunnerProperty.set(commandRunner) it.mobileProvisioningList.set(xcodeBuildPluginExtension.signing.mobileProvisionList) it.outputDirectory.set(xcodeBuildPluginExtension.signing.provisioningDestinationRoot) it.plistHelperProperty.set(plistHelper) + it.plistHelperProperty.set(plistHelper) // We use the result of the task to populate the read only value xcodeBuildPluginExtension.signing diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 2f9c2328..050a67c3 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -1,7 +1,9 @@ package org.openbakery.signing import org.gradle.api.Project +import org.gradle.api.Transformer import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property @@ -9,17 +11,22 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.Internal import org.openbakery.CommandRunner import org.openbakery.codesign.CodesignParameters +import org.openbakery.util.PathHelper import javax.inject.Inject +import java.util.regex.Matcher +import java.util.regex.Pattern class Signing { final DirectoryProperty signingDestinationRoot = project.layout.directoryProperty() final DirectoryProperty provisioningDestinationRoot = project.layout.directoryProperty() final Property certificatePassword + final Property certificateFriendlyName final Property timeout = project.objects.property(Integer) final Property signingMethod = project.objects.property(SigningMethod) final RegularFileProperty certificate + final RegularFileProperty entitlementsFile final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() final ListProperty mobileProvisionList = project.objects.listProperty(String) @@ -30,14 +37,15 @@ class Signing { @Internal Object keychainPathInternal - public final static KEYCHAIN_NAME_BASE = "gradle-" + @Internal + final RegularFileProperty xcConfigFile + + public static final String KEYCHAIN_NAME_BASE = "gradle-" + private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ String identity String plugin - Object entitlementsFile - - Map entitlements /** * internal parameters @@ -54,11 +62,26 @@ class Signing { this.project = project this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) + this.certificate = project.layout.fileProperty() this.certificatePassword = project.objects.property(String) + this.certificateFriendlyName = project.objects.property(String) + this.certificateFriendlyName.set(certificate.map(new Transformer() { + @Override + String transform(RegularFile regularFile) { + return getSignatureFriendlyName(regularFile.asFile) + } + })) + this.commandRunner = new CommandRunner() + this.entitlementsFile = project.layout.fileProperty() + this.keyChainFile.set(signingDestinationRoot.file(keychainName)) this.timeout.set(3600) + + this.xcConfigFile = project.layout.fileProperty() + this.xcConfigFile.set(project.layout.buildDirectory.file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) +// PathHelper.resolveXcConfigFile(project)) } void setKeychain(Object keychain) { @@ -87,23 +110,8 @@ class Signing { this.mobileProvisionList.add(value) } - File getEntitlementsFile() { - if (entitlementsFile != null) { - if (entitlementsFile instanceof File) { - return entitlementsFile - } - return project.file(entitlementsFile) - - } - return null - } - boolean hasEntitlementsFile() { - return entitlementsFile != null && entitlementsFile.exists() - } - - void setEntitlementsFile(Object entitlementsFile) { - this.entitlementsFile = entitlementsFile + return entitlementsFile.present } String getIdentity() { @@ -148,5 +156,27 @@ class Signing { return result } + String getSignatureFriendlyName(File file) { + return Optional.ofNullable(getKeyContent(file) + .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) { + return commandRunner.runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + certificatePassword.get()]) + } } From fb5d8fb00302815fb297ec3c09f5853f67cf7663 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 14 May 2018 11:55:49 +0100 Subject: [PATCH 086/121] Tweak units test post changes --- ...PrepareXcodeArchivingFunctionalTest.groovy | 80 ++++++++-------- .../resources/fake.entitlements | 0 .../PrepareXcodeArchivingTask.groovy | 27 ++++-- .../PrepareXcodeArchivingTaskTest.groovy | 96 +++++++++++++++++++ 4 files changed, 156 insertions(+), 47 deletions(-) create mode 100644 plugin/src/functionalTest/resources/fake.entitlements create mode 100644 plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy index bbbf3b4d..b5d09833 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -8,7 +8,6 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import org.openbakery.util.PathHelper import spock.lang.Specification -import spock.lang.Unroll import java.nio.file.Paths @@ -69,48 +68,31 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { + PrepareXcodeArchivingTask.DESCRIPTION) } - @Unroll("It should fail to resolve provisioning for bundleIdentifier : #bundleIdentifier") - def "Should try to resolve provisioning for the bundle identifier"() { + def "The task should complete without error and generate the xcconfig file"() { setup: setupBuildFile() when: - if (bundleIdentifier != null) { - buildFile << """ + buildFile << """ xcodebuild { infoplist { - bundleIdentifier = "$bundleIdentifier" + bundleIdentifier = "org.openbakery.test.ExampleWidget" } } """ - } - - BuildResult result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments(PrepareXcodeArchivingTask.NAME) - .withPluginClasspath(pluginClasspath) - .buildAndFail() - - then: "The build should fail due to invalidate configuration" - result.output.contains("> Cannot resolve a valid provisioning profile for bundle identifier : " - + exceptionValue) - - where: - bundleIdentifier | exceptionValue - null | "\$(PRODUCT_BUNDLE_IDENTIFIER)" - "invalid.bundle.identifier" | "invalid.bundle.identifier" - } - - def "The task should fail due to invalid configuration"() { - setup: - setupBuildFile() - when: + 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" + } } """ @@ -118,13 +100,33 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { .withProjectDir(testProjectDir.root) .withArguments(PrepareXcodeArchivingTask.NAME) .withPluginClasspath(pluginClasspath) - .buildAndFail() + .build() + + then: "The task should complete without error" - then: "The build should fail due to invalidate configuration" - result.output.contains("The signing certificate password is not defined") + result.task(":" + PrepareXcodeArchivingTask.NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The archive xcconfig file 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 "The task should complete without error and generate the xcconfig file"() { + def "If present the entitlements file should be present into the xcconfig file"() { setup: setupBuildFile() @@ -139,6 +141,10 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { final File certificate = findResource("fake_distribution.p12") assert certificate.exists() + + final File entitlementsFile = findResource("fake.entitlements") + assert entitlementsFile.exists() + buildFile << """ xcodebuild { infoplist { @@ -148,11 +154,11 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { signing { certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" + entitlementsFile = project.file("${entitlementsFile.absolutePath}") } } """ - BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments(PrepareXcodeArchivingTask.NAME) @@ -164,7 +170,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { result.task(":" + PrepareXcodeArchivingTask.NAME) .outcome == TaskOutcome.SUCCESS - and: "The archive xcconfig file should be properly generated and populated from configured values" + and: "The archive xcconfig should contains the path to the entitlements file" File outputFile = new File(testProjectDir.root, "build/" + PathHelper.FOLDER_ARCHIVE @@ -173,11 +179,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { 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") + text.contains("CODE_SIGN_ENTITLEMENTS = ${entitlementsFile.absolutePath}") } private File findResource(String name) { diff --git a/plugin/src/functionalTest/resources/fake.entitlements b/plugin/src/functionalTest/resources/fake.entitlements new file mode 100644 index 00000000..e69de29b diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index b44e8123..d060bf37 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -23,11 +23,11 @@ class PrepareXcodeArchivingTask extends DefaultTask { @OutputFile final Provider outputFile = newOutputFile() + final ListProperty registeredProvisioningFiles = project.objects.listProperty(File) final Property commandRunnerProperty = project.objects.property(CommandRunner) final Property plistHelperProperty = project.objects.property(PlistHelper) - final ListProperty registeredProvisioningFiles = project.objects.listProperty(File) - final Property configurationBundleIdentifier = project.objects.property(String) final Property certificateFriendlyName = project.objects.property(String) + final Property configurationBundleIdentifier = project.objects.property(String) @Internal private Property entitlementsFilePath = project.objects.property(String) @@ -41,12 +41,12 @@ class PrepareXcodeArchivingTask extends DefaultTask { public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" - private static final String KEY_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER" - private static final String KEY_CODE_SIGN_IDENTITY = "CODE_SIGN_IDENTITY" - private static final String KEY_CODE_SIGN_ENTITLEMENTS = "CODE_SIGN_ENTITLEMENTS" - private static final String KEY_DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM" - private static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" - private static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" + 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" + static final String KEY_PROVISIONING_PROFILE_ID = "PROVISIONING_PROFILE" + static final String KEY_PROVISIONING_PROFILE_SPEC = "PROVISIONING_PROFILE_SPECIFIER" PrepareXcodeArchivingTask() { super() @@ -82,10 +82,20 @@ class PrepareXcodeArchivingTask extends DefaultTask { commandRunnerProperty.get()) } })) + + this.onlyIf { + return certificateFriendlyName.present && + configurationBundleIdentifier.present && + provisioningForConfiguration.present && + outputFile.present && + provisioningForConfiguration.present + } } @TaskAction void generate() { + logger.lifecycle("Preparing archiving") + outputFile.get().asFile.text = "" append(KEY_CODE_SIGN_IDENTITY, certificateFriendlyName.get()) @@ -108,4 +118,5 @@ class PrepareXcodeArchivingTask extends DefaultTask { .asFile .append(System.getProperty("line.separator") + key + " = " + value) } + } diff --git a/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy new file mode 100644 index 00000000..f4da596f --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy @@ -0,0 +1,96 @@ +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.signing.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 d8aaf774eab875c4950b7672471c9988a2692934 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Mon, 14 May 2018 13:39:47 +0100 Subject: [PATCH 087/121] Start to convert the packaging task --- .../PrepareXcodeArchivingTask.groovy | 12 +++------ .../XcodeBuildPluginExtension.groovy | 25 +++++++++++++++++++ .../groovy/org/openbakery/XcodePlugin.groovy | 3 +++ .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 22 ++++++++++------ 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index d060bf37..768951d0 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -25,18 +25,12 @@ class PrepareXcodeArchivingTask extends DefaultTask { final ListProperty registeredProvisioningFiles = project.objects.listProperty(File) final Property commandRunnerProperty = project.objects.property(CommandRunner) + final Property provisioningForConfiguration = project.objects.property(File) final Property plistHelperProperty = project.objects.property(PlistHelper) + final Property provisioningReader = project.objects.property(ProvisioningProfileReader) final Property certificateFriendlyName = project.objects.property(String) final Property configurationBundleIdentifier = project.objects.property(String) - - @Internal - private Property entitlementsFilePath = project.objects.property(String) - - @Internal - final Property provisioningForConfiguration = project.objects.property(File) - - @Internal - final Property provisioningReader = project.objects.property(ProvisioningProfileReader) + final Property entitlementsFilePath = project.objects.property(String) public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 142a44f7..9440a3a9 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -18,6 +18,10 @@ package org.openbakery import org.apache.commons.io.filefilter.SuffixFileFilter import org.apache.commons.lang.StringUtils import org.gradle.api.Project +import org.gradle.api.Transformer +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil import org.openbakery.signing.Signing @@ -33,6 +37,9 @@ class XcodeBuildPluginExtension { final Property version final Property scheme + final DirectoryProperty archiveDirectory + final RegularFileProperty schemeArchiveFile + final Signing signing @@ -92,6 +99,10 @@ class XcodeBuildPluginExtension { this.version = project.objects.property(String) this.scheme = project.objects.property(String) + this.archiveDirectory = project.layout.directoryProperty() + this.schemeArchiveFile = project.layout.fileProperty() + configurePaths() + this.signing = project.objects.newInstance(Signing, project) this.variableResolver = new VariableResolver(project) @@ -120,6 +131,20 @@ class XcodeBuildPluginExtension { } + private void configurePaths() { + this.archiveDirectory.set(project.layout + .buildDirectory + .dir(PathHelper.FOLDER_ARCHIVE)) + + this.schemeArchiveFile.set(scheme.map(new Transformer() { + @Override + RegularFile transform(String scheme) { + return archiveDirectory.get() + .file(scheme + PathHelper.EXTENSION_XCARCHIVE) + } + })) + } + Optional getBuildTargetConfiguration(String schemeName, String configuration) { return Optional.ofNullable(projectSettings.get(schemeName, null)) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index ab815ea2..31262eb3 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -500,7 +500,10 @@ class XcodePlugin implements Plugin { project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) { it.setGroup(XCODE_GROUP_NAME) + it.commandRunnerProperty.set(commandRunner) + it.outputArchiveFile.set(xcodeBuildPluginExtension.schemeArchiveFile) it.scheme.set(xcodeBuildPluginExtension.scheme) + it.xcConfigFile.set(xcodeBuildPluginExtension.signing.xcConfigFile) } XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask = project.getTasks(). diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 50c90182..72a390b2 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -2,10 +2,13 @@ package org.openbakery.archiving import groovy.transform.CompileStatic import org.gradle.api.Task +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.* import org.openbakery.AbstractXcodeBuildTask +import org.openbakery.CommandRunner import org.openbakery.PrepareXcodeArchivingTask import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper @@ -19,6 +22,14 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input final Provider scheme = project.objects.property(String) + @InputFile + final Property xcConfigFile = newInputFile() + + @OutputFile + final Provider outputArchiveFile = newOutputFile() + + final Property commandRunnerProperty = project.objects.property(CommandRunner) + public static final String NAME = "archiveXcodeBuild" XcodeBuildArchiveTaskIosAndTvOS() { @@ -38,11 +49,6 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { }) } - @InputFile - File getXcConfigFile() { - return PathHelper.resolveXcConfigFile(project) - } - @OutputFile File getOutputTextFile() { return PathHelper.resolveArchivingLogFile(project) @@ -58,7 +64,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { @TaskAction private void archive() { Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, - commandRunner, + commandRunnerProperty.get(), xcode, parameters, getDestinations()) @@ -66,7 +72,7 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { commandRunner.setOutputFile(getOutputTextFile()) xcodeBuild.archive(scheme.get(), - PathHelper.resolveArchiveFile(project, scheme.get()), - getXcConfigFile()) + outputArchiveFile.get().asFile, + xcConfigFile.get().asFile) } } From 663b4029dbf1cdf37026c03754ed8d09084af251 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 11:31:35 +0100 Subject: [PATCH 088/121] Add Xcode service add unit test to the XcodeBuildArchiveTaskIosAndTvOS task --- .../org/openbakery/xcode/Version.groovy | 8 +- .../groovy/org/openbakery/xcode/Xcode.groovy | 302 +++++++++--------- .../org/openbakery/xcode/Xcodebuild.groovy | 34 +- .../openbakery/AbstractXcodeBuildTask.groovy | 6 +- .../XcodeBuildPluginExtension.groovy | 33 +- .../org/openbakery/XcodeBuildTask.groovy | 11 + .../groovy/org/openbakery/XcodePlugin.groovy | 9 +- .../groovy/org/openbakery/XcodeService.groovy | 93 ++++++ .../XcodeBuildArchiveTaskIosAndTvOS.groovy | 82 +++-- .../XcodeBuildLegacyArchiveTask.groovy | 6 +- ...XcodeBuildArchiveTaskIosAndTvOSTest.groovy | 74 +++++ 11 files changed, 441 insertions(+), 217 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/XcodeService.groovy create mode 100644 plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy index c373cb42..0652acf1 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Version.groovy @@ -1,6 +1,6 @@ package org.openbakery.xcode -class Version implements Comparable { +class Version implements Comparable, Serializable { public int major = -1 public int minor = -1 @@ -11,7 +11,7 @@ class Version implements Comparable { public Version() { } - public Version(String version) { + public Version(String version) { Scanner versionScanner = new Scanner(version); versionScanner.useDelimiter("\\."); @@ -69,13 +69,13 @@ class Version implements Comparable { builder.append(minor) } - if (this.maintenance>= 0) { + if (this.maintenance >= 0) { builder.append(".") builder.append(maintenance) } if (this.suffix != null) { - if (builder.length() > 0 ){ + if (builder.length() > 0) { builder.append(".") } builder.append(suffix) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index 8b539f9e..ca26a525 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -11,153 +11,157 @@ import java.util.regex.Pattern @CompileStatic class Xcode { - private Version version = null - private String xcodePath - - @VisibleForTesting - private CommandRunner commandRunner - - public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" - public static final String XCODE_ACTION_XC_SELECT = "xcode-select" - public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" - public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" - public static final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" - - private final Logger logger = LoggerFactory.getLogger(Xcode.class) - - private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ - - Xcode(CommandRunner commandRunner) { - this(commandRunner, null) - } - - Xcode(CommandRunner commandRunner, String version) { - logger.debug("create xcode with version {}", version) - this.commandRunner = commandRunner - if (version != null) { - setVersionFromString(version) - } - } - - CommandRunner getCommandRunner() { - return commandRunner - } - - /** - * Provide the environments values to provide to the command line runner to select - * a Xcode version without using `xcode-select -s` who requires `sudo`. - * - * @param version : The required Xcode version - * @return A map of environment variables to pass to the command runner - */ - Map getXcodeSelectEnvValue(String version) { - setVersionFromString(version) - File file = new File(xcodePath, XCODE_CONTENT_DEVELOPER) - HashMap result = new HashMap() - if (file.exists()) { - result.put(ENV_DEVELOPER_DIR, file.absolutePath) - } - return result - } - - void setVersionFromString(String version) throws IllegalArgumentException { - if (version == null) { - throw new IllegalArgumentException() - } - - final Version requiredVersion = new Version(version) - - Optional result = Optional.ofNullable(resolveInstalledXcodeVersionsList() - .split("\n") - .iterator() - .collect { new File(it as File, XCODE_CONTENT_XCODE_BUILD) } - .findAll { it.exists() } - .find { - Version candidate = getXcodeVersion(it.absolutePath) - - boolean versionStartWith = candidate.toString() - .startsWith(requiredVersion.toString()) - - boolean versionHasSuffix = (candidate.suffix != null - && requiredVersion.suffix != null - && candidate.suffix.equalsIgnoreCase(requiredVersion.suffix)) - - return versionHasSuffix || versionStartWith - }) - - if (result.isPresent()) { - selectXcode(result.get()) - } else { - throw new IllegalStateException("No Xcode found with build number " + version) - } - } - - void selectXcode(File file) { - String absolutePath = file.absolutePath - Version xcodeVersion = getXcodeVersion(absolutePath) - xcodePath = new File(absolutePath - XCODE_CONTENT_XCODE_BUILD) - this.version = xcodeVersion - } - - String resolveInstalledXcodeVersionsList() { - return commandRunner.runWithResult("mdfind", - "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") - } - - Version getXcodeVersion(String xcodeBuildCommand) { - String xcodeVersion = commandRunner.runWithResult(xcodeBuildCommand, - "-version") - - Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) - if (matcher.matches()) { - Version version = new Version(matcher.group(1)) - version.suffix = matcher.group(2) - return version - } - return null - } - - Version getVersion() { - if (this.version == null) { - this.version = getXcodeVersion(getXcodebuild()) - } - return this.version - } - - String getPath() { - if (xcodePath == null) { - String result = commandRunner.runWithResult(XCODE_ACTION_XC_SELECT - , "-p") - xcodePath = result - "/$XCODE_CONTENT_DEVELOPER" - } - return xcodePath - } - - String getXcodebuild() { - if (xcodePath != null) { - return new File(xcodePath, XCODE_CONTENT_XCODE_BUILD).absolutePath - } - return "xcodebuild" - } - - String getAltool() { - return getPath() + "/Contents/Applications/Application Loader" + - ".app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" - } - - String getXcrun() { - return getPath() + XCODE_CONTENT_XC_RUN - } - - String getSimctl() { - return getPath() + "/$XCODE_CONTENT_DEVELOPER/usr/bin/simctl" - } - - @Override - String toString() { - return "Xcode{" + - "xcodePath='" + xcodePath + '\'' + - ", version=" + version + - '}' - } + private Version version = null + private String xcodePath + + @VisibleForTesting + private CommandRunner commandRunner + + public static final String ENV_DEVELOPER_DIR = "DEVELOPER_DIR" + public static final String XCODE_ACTION_XC_SELECT = "xcode-select" + public static final String XCODE_CONTENT_DEVELOPER = "Contents/Developer" + public static final String XCODE_CONTENT_XC_RUN = "/$XCODE_CONTENT_DEVELOPER/usr/bin/xcrun" + public static + final String XCODE_CONTENT_XCODE_BUILD = "$XCODE_CONTENT_DEVELOPER/usr/bin/xcodebuild" + + private final Logger logger = LoggerFactory.getLogger(Xcode.class) + + private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ + + Xcode(CommandRunner commandRunner) { + this(commandRunner, null) + } + + Xcode(CommandRunner commandRunner, String version) { + logger.debug("create xcode with version {}", version) + this.commandRunner = commandRunner + if (version != null) { + setVersionFromString(version) + } + } + + CommandRunner getCommandRunner() { + return commandRunner + } + + /** + * Provide the environments values to provide to the command line runner to select + * a Xcode version without using `xcode-select -s` who requires `sudo`. + * + * @param version : The required Xcode version + * @return A map of environment variables to pass to the command runner + */ + Map getXcodeSelectEnvValue(String version) { + setVersionFromString(version) + File file = new File(xcodePath, XCODE_CONTENT_DEVELOPER) + HashMap result = new HashMap() + if (file.exists()) { + result.put(ENV_DEVELOPER_DIR, file.absolutePath) + } + println file.absolutePath + return result + } + + void setVersionFromString(String version) throws IllegalArgumentException { + assert version != null + + Optional result = resolveXcodeInstallOfVersion(version) + + if (result.isPresent()) { + selectXcode(result.get()) + } else { + throw new IllegalStateException("No Xcode found with build number " + version) + } + } + + Optional resolveXcodeInstallOfVersion(String version) { + final Version requiredVersion = new Version(version) + + return Optional.ofNullable(resolveInstalledXcodeVersionsList() + .split("\n") + .iterator() + .collect { new File(it as File, XCODE_CONTENT_XCODE_BUILD) } + .findAll { it.exists() } + .find { + Version candidate = getXcodeVersion(it.absolutePath) + + boolean versionStartWith = candidate.toString() + .startsWith(requiredVersion.toString()) + + boolean versionHasSuffix = (candidate.suffix != null + && requiredVersion.suffix != null + && candidate.suffix.equalsIgnoreCase(requiredVersion.suffix)) + + return versionHasSuffix || versionStartWith + }) + } + + void selectXcode(File file) { + String absolutePath = file.absolutePath + Version xcodeVersion = getXcodeVersion(absolutePath) + xcodePath = new File(absolutePath - XCODE_CONTENT_XCODE_BUILD) + this.version = xcodeVersion + } + + String resolveInstalledXcodeVersionsList() { + return commandRunner.runWithResult("mdfind", + "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + } + + Version getXcodeVersion(String xcodeBuildCommand) { + String xcodeVersion = commandRunner.runWithResult(xcodeBuildCommand, + "-version") + + Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) + if (matcher.matches()) { + Version version = new Version(matcher.group(1)) + version.suffix = matcher.group(2) + return version + } + return null + } + + Version getVersion() { + if (this.version == null) { + this.version = getXcodeVersion(getXcodebuild()) + } + return this.version + } + + String getPath() { + if (xcodePath == null) { + String result = commandRunner.runWithResult(XCODE_ACTION_XC_SELECT + , "-p") + xcodePath = result - "/$XCODE_CONTENT_DEVELOPER" + } + return xcodePath + } + + String getXcodebuild() { + if (xcodePath != null) { + return new File(xcodePath, XCODE_CONTENT_XCODE_BUILD).absolutePath + } + return "xcodebuild" + } + + String getAltool() { + return getPath() + "/Contents/Applications/Application Loader" + + ".app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool" + } + + String getXcrun() { + return getPath() + XCODE_CONTENT_XC_RUN + } + + String getSimctl() { + return getPath() + "/$XCODE_CONTENT_DEVELOPER/usr/bin/simctl" + } + + @Override + String toString() { + return "Xcode{" + + "xcodePath='" + xcodePath + '\'' + + ", version=" + version + + '}' + } } diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index b9a817db..c325eca5 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -3,10 +3,11 @@ package org.openbakery.xcode import org.openbakery.CommandRunner import org.openbakery.output.OutputAppender +import javax.annotation.Nullable + class Xcodebuild { CommandRunner commandRunner - HashMap buildSettings = null File projectDirectory @@ -61,22 +62,27 @@ class Xcodebuild { ARGUMENT_EXPORT_OPTIONS_PLIST, exportOptionsPlist.absolutePath) } - public void archive(String scheme, - File outputPath, - File xcConfig) { - outputPath.mkdirs() - - println "version : " + xcode.version - + public static void archive(CommandRunner commandRunner, + String scheme, + File outputPath, + File xcConfig, + @Nullable File xcodeApp) { assert scheme != null - assert outputPath.isDirectory() assert xcConfig.exists() && !xcConfig.isDirectory() - commandRunner.run(EXECUTABLE, - ACTION_ARCHIVE, - ARGUMENT_SCHEME, scheme, - ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, - ARGUMENT_XCCONFIG, xcConfig.absolutePath) + HashMap envMap = new HashMap<>() + + if (xcodeApp != null) { + envMap.put(Xcode.ENV_DEVELOPER_DIR, xcodeApp.absolutePath) + } + + List args = [EXECUTABLE, + ACTION_ARCHIVE, + ARGUMENT_SCHEME, scheme, + ARGUMENT_ARCHIVE_PATH, outputPath.absolutePath, + ARGUMENT_XCCONFIG, xcConfig.absolutePath] + + commandRunner.run(args, envMap) } def execute(OutputAppender outputAppender, Map environment) { diff --git a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy index 25424c26..b50c49a7 100644 --- a/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/AbstractXcodeBuildTask.groovy @@ -95,9 +95,9 @@ abstract class AbstractXcodeBuildTask extends AbstractXcodeTask { XcodeBuildOutputAppender createXcodeBuildOutputAppender(String name) { - StyledTextOutput output = getServices().get(StyledTextOutputFactory.class).create(XcodeBuildTask.class, LogLevel.LIFECYCLE); - ProgressLoggerFactory progressLoggerFactory = getServices().get(ProgressLoggerFactory.class); - ProgressLogger progressLogger = progressLoggerFactory.newOperation(XcodeBuildTask.class).start(name, name); + StyledTextOutput output = getServices().get(StyledTextOutputFactory.class).create(XcodeBuildTask.class, LogLevel.LIFECYCLE) + ProgressLoggerFactory progressLoggerFactory = getServices().get(ProgressLoggerFactory.class) + ProgressLogger progressLogger = progressLoggerFactory.newOperation(XcodeBuildTask.class).start(name, name) return new XcodeBuildOutputAppender(progressLogger, output) } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 9440a3a9..501f720c 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -19,9 +19,8 @@ import org.apache.commons.io.filefilter.SuffixFileFilter import org.apache.commons.lang.StringUtils import org.gradle.api.Project import org.gradle.api.Transformer +import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil import org.openbakery.signing.Signing @@ -38,7 +37,8 @@ class XcodeBuildPluginExtension { final Property version final Property scheme final DirectoryProperty archiveDirectory - final RegularFileProperty schemeArchiveFile + final DirectoryProperty schemeArchiveFile + final Property xcodeServiceProperty final Signing signing @@ -65,7 +65,7 @@ class XcodeBuildPluginExtension { String bundleNameSuffix = null List arch = null String workspace = null - String xcodeVersion = null + Map environment = null String productName = null String bundleName = null @@ -95,19 +95,22 @@ class XcodeBuildPluginExtension { private final Project project public XcodeBuildPluginExtension(Project project) { + commandRunner = new CommandRunner() + plistHelper = new PlistHelper(commandRunner) + this.project = project; this.version = project.objects.property(String) this.scheme = project.objects.property(String) + this.xcodeServiceProperty = project.objects.property(XcodeService) this.archiveDirectory = project.layout.directoryProperty() - this.schemeArchiveFile = project.layout.fileProperty() + this.schemeArchiveFile = project.layout.directoryProperty() + + configureServices() configurePaths() this.signing = project.objects.newInstance(Signing, project) - this.variableResolver = new VariableResolver(project) - commandRunner = new CommandRunner() - plistHelper = new PlistHelper(commandRunner) this.dstRoot = { return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("dst") @@ -128,7 +131,13 @@ class XcodeBuildPluginExtension { this.derivedDataPath = { return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("derivedData") } + } + private void configureServices() { + XcodeService service = project.objects.newInstance(XcodeService, + project) + service.commandRunnerProperty.set(commandRunner) + this.xcodeServiceProperty.set(service) } private void configurePaths() { @@ -136,11 +145,11 @@ class XcodeBuildPluginExtension { .buildDirectory .dir(PathHelper.FOLDER_ARCHIVE)) - this.schemeArchiveFile.set(scheme.map(new Transformer() { + this.schemeArchiveFile.set(scheme.map(new Transformer() { @Override - RegularFile transform(String scheme) { + Directory transform(String scheme) { return archiveDirectory.get() - .file(scheme + PathHelper.EXTENSION_XCARCHIVE) + .dir(scheme + PathHelper.EXTENSION_XCARCHIVE) } })) } @@ -472,7 +481,7 @@ class XcodeBuildPluginExtension { // should be remove in the future, so that every task has its own xcode object Xcode getXcode() { if (xcode == null) { - xcode = new Xcode(commandRunner, xcodeVersion) + xcode = new Xcode(commandRunner, version.get()) } logger.debug("using xcode {}", xcode) return xcode diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildTask.groovy index fe438758..494b0c34 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildTask.groovy @@ -15,7 +15,10 @@ */ package org.openbakery +import org.gradle.api.Task +import org.gradle.api.specs.Spec import org.gradle.api.tasks.TaskAction +import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild class XcodeBuildTask extends AbstractXcodeBuildTask { @@ -28,6 +31,14 @@ class XcodeBuildTask extends AbstractXcodeBuildTask { XcodePlugin.INFOPLIST_MODIFY_TASK_NAME, ) this.description = "Builds the Xcode project" + + onlyIf(new Spec() { + @Override + boolean isSatisfiedBy(Task task) { + return getXcodeExtension().getType() == Type.macOS || + getXcodeExtension().getType() == Type.watchOS + } + }) } @TaskAction diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 31262eb3..c4edf50e 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -59,6 +59,7 @@ import org.openbakery.packaging.PackageTaskIosAndTvOS import org.openbakery.signing.* import org.openbakery.simulators.* import org.openbakery.util.PlistHelper +import org.openbakery.xcode.Xcode import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -139,11 +140,12 @@ class XcodePlugin implements Plugin { private CommandRunner commandRunner private PlistHelper plistHelper private Security securityTool + private Xcode xcode void apply(Project project) { project.getPlugins().apply(BasePlugin.class); - System.setProperty("java.awt.headless", "true"); + System.setProperty("java.awt.headless", "true") setupTools(project) configureExtensions(project) configureClean(project) @@ -171,6 +173,7 @@ class XcodePlugin implements Plugin { void setupTools(Project project) { this.commandRunner = new CommandRunner() + this.xcode = new Xcode(commandRunner) this.plistHelper = new PlistHelper(commandRunner) this.securityTool = new Security(commandRunner) } @@ -500,10 +503,14 @@ class XcodePlugin implements Plugin { project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, XcodeBuildArchiveTaskIosAndTvOS.class) { it.setGroup(XCODE_GROUP_NAME) + it.buildType.set(xcodeBuildPluginExtension.type) 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(xcodeBuildPluginExtension.signing.xcConfigFile) + it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } XcodeBuildLegacyArchiveTask xcodeBuildArchiveTask = project.getTasks(). diff --git a/plugin/src/main/groovy/org/openbakery/XcodeService.groovy b/plugin/src/main/groovy/org/openbakery/XcodeService.groovy new file mode 100644 index 00000000..4b26a96b --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/XcodeService.groovy @@ -0,0 +1,93 @@ +package org.openbakery + +import org.gradle.api.Project +import org.gradle.api.Transformer +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.openbakery.XcodeService.XcodeApp +import org.openbakery.xcode.Version + +import javax.inject.Inject +import java.util.regex.Matcher +import java.util.regex.Pattern + +class XcodeService { + + final Property commandRunnerProperty + final ListProperty installedXcodes + + private static final String CONTENT_DEVELOPER = "Contents/Developer" + private static final String CONTENT_XCODE_BUILD = "$CONTENT_DEVELOPER/usr/bin/xcodebuild" + private static final Pattern VERSION_PATTERN = ~/Xcode\s([^\s]*)\nBuild\sversion\s([^\s]*)/ + + @Inject + XcodeService(Project project) { + commandRunnerProperty = project.objects.property(CommandRunner) + + installedXcodes = project.objects.listProperty(XcodeApp) + installedXcodes.set(commandRunnerProperty.map(new Transformer, CommandRunner>() { + @Override + List transform(CommandRunner commandRunner) { + return commandRunner.runWithResult("mdfind", + "kMDItemCFBundleIdentifier=com.apple.dt.Xcode") + .split("\n") + .collect { new File(it) } + .collect { new XcodeApp(it, getXcodeVersion(commandRunner, it)) } + } + })) + } + + public XcodeApp getInstallationForVersion(final String version) { + return installedXcodes.map(new Transformer>() { + @Override + XcodeApp transform(List xcodeApps) { + return xcodeApps.find { it.version.toString().startsWith(version) } + } + }).getOrNull() + } + + private Version getXcodeVersion(CommandRunner commandRunner, + File file) { + String xcodeVersion = commandRunner.runWithResult( + new File(file, CONTENT_XCODE_BUILD).absolutePath, + "-version") + + Matcher matcher = VERSION_PATTERN.matcher(xcodeVersion) + if (matcher.matches()) { + Version version = new Version(matcher.group(1)) + version.suffix = matcher.group(2) + + return version + } + + return null + } + + static class XcodeApp implements Serializable { + private final File file + private final Version version + + XcodeApp(File file, + Version version) { + this.file = file + this.version = version + } + + File getFile() { + return file + } + + File getContentXcodeBuildFile() { + return new File(file, CONTENT_XCODE_BUILD) + } + + File getContentDeveloperFile() { + return new File(file, CONTENT_DEVELOPER) + } + + Version getVersion() { + return version + } + } + +} diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy index 72a390b2..f1ebe023 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOS.groovy @@ -1,33 +1,46 @@ 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.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.* -import org.openbakery.AbstractXcodeBuildTask +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 import org.openbakery.PrepareXcodeArchivingTask +import org.openbakery.XcodeService import org.openbakery.signing.ProvisioningInstallTask -import org.openbakery.util.PathHelper import org.openbakery.xcode.Type +import org.openbakery.xcode.Xcode import org.openbakery.xcode.Xcodebuild @CompileStatic -@CacheableTask -class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { +class XcodeBuildArchiveTaskIosAndTvOS extends DefaultTask { + + @Input + final Provider xcodeVersion = project.objects.property(String) @Input final Provider scheme = project.objects.property(String) + @Input + final Provider buildType = project.objects.property(Type) + @InputFile final Property xcConfigFile = newInputFile() - @OutputFile - final Provider outputArchiveFile = newOutputFile() + @OutputDirectory + final Provider outputArchiveFile = newOutputDirectory() + final Property xcodeServiceProperty = project.objects.property(XcodeService) + final Property xcode = project.objects.property(Xcode) final Property commandRunnerProperty = project.objects.property(CommandRunner) public static final String NAME = "archiveXcodeBuild" @@ -38,41 +51,48 @@ class XcodeBuildArchiveTaskIosAndTvOS extends AbstractXcodeBuildTask { dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(PrepareXcodeArchivingTask.NAME) - this.description = "Use the xcodebuild archiver to create the project archive" + this.description = "Use the XcodeBuild archive command line to create the project archive" onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { - return getXcodeExtension().getType() == Type.iOS || - getXcodeExtension().getType() == Type.tvOS + return buildType.get() == Type.iOS || buildType.get() == Type.tvOS } }) } - @OutputFile - File getOutputTextFile() { - return PathHelper.resolveArchivingLogFile(project) - } - - @OutputDirectory - File getOutputDirectory() { - File archiveDirectory = PathHelper.resolveArchiveFolder(project) - archiveDirectory.mkdirs() - return archiveDirectory - } - @TaskAction - private void archive() { - Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, - commandRunnerProperty.get(), - xcode, - parameters, - getDestinations()) + void archive() { + assert scheme.present: "No target scheme configured" + assert outputArchiveFile.present: "No output file folder configured" + assert xcConfigFile.present: "No 'xcconfig' file configured" - commandRunner.setOutputFile(getOutputTextFile()) + logger.lifecycle("Archive project with configuration: " + + "\n\tScheme : ${scheme.get()} " + + "\n\tXcode version : ${xcodeVersion.getOrElse("System default")}") - xcodeBuild.archive(scheme.get(), + + Xcodebuild.archive(commandRunnerProperty.get(), + scheme.get(), outputArchiveFile.get().asFile, - xcConfigFile.get().asFile) + xcConfigFile.get().asFile, + getXcodeAppForConfiguration().getOrNull()) + } + + private Provider getXcodeAppForConfiguration() { + + Provider xcodeApp + if (xcodeVersion.present) { + xcodeApp = xcodeServiceProperty.map(new Transformer() { + @Override + File transform(XcodeService xcodeService) { + XcodeService.XcodeApp app = xcodeService.getInstallationForVersion(xcodeVersion.get()) + return app.contentDeveloperFile + } + }) + } else { + xcodeApp = project.objects.property(File) + } + return xcodeApp } } diff --git a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy index b21f043b..41cd5080 100644 --- a/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/archiving/XcodeBuildLegacyArchiveTask.groovy @@ -41,9 +41,6 @@ class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { XcodeBuildLegacyArchiveTask() { super() - dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME, - ProvisioningInstallTask.TASK_NAME) - this.description = "Use the legacy archiver to create the project archive" onlyIf(new Spec() { @@ -53,6 +50,9 @@ class XcodeBuildLegacyArchiveTask extends AbstractXcodeBuildTask { getXcodeExtension().getType() == Type.watchOS } }) + + dependsOn(XcodePlugin.XCODE_BUILD_TASK_NAME, + ProvisioningInstallTask.TASK_NAME) } diff --git a/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy b/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy new file mode 100644 index 00000000..74ff6234 --- /dev/null +++ b/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy @@ -0,0 +1,74 @@ +package org.openbakery.archiving + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.ExpectedException +import org.junit.rules.TemporaryFolder +import org.openbakery.CommandRunner +import org.openbakery.XcodePlugin +import org.openbakery.XcodeService +import org.openbakery.xcode.Type +import spock.lang.Shared +import spock.lang.Specification + +import static org.openbakery.xcode.Xcodebuild.* + +class XcodeBuildArchiveTaskIosAndTvOSTest extends Specification { + + @Rule + public ExpectedException exception = ExpectedException.none() + + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + Project project + XcodeBuildArchiveTaskIosAndTvOS subject + CommandRunner mockCommandRunner = Mock(CommandRunner) + XcodeService.XcodeApp mockXcodeApp = Mock(XcodeService.XcodeApp) + XcodeService mockXcodeService = Mock(XcodeService) + File outputDir + File fakeXccConfig + + @Shared + File fakeXcodeRuntime + + private static final String TEST_SCHEME = "test-scheme" + + void setup() { + project = ProjectBuilder.builder() + .withProjectDir(testProjectDir.root) + .build() + + project.buildDir = testProjectDir.newFile("build.gradle") + project.apply plugin: XcodePlugin + + outputDir = testProjectDir.newFolder("output") + fakeXccConfig = testProjectDir.newFile("test.xcconfig") + fakeXcodeRuntime = testProjectDir.newFile("test.app") + + subject = project.getTasks().getByName(XcodeBuildArchiveTaskIosAndTvOS.NAME) as XcodeBuildArchiveTaskIosAndTvOS + assert subject != null + + subject.xcodeServiceProperty.set(mockXcodeService) + subject.commandRunnerProperty.set(mockCommandRunner) + subject.scheme.set(TEST_SCHEME) + subject.buildType.set(Type.iOS) + subject.outputArchiveFile.set(outputDir) + subject.xcConfigFile.set(fakeXccConfig) + } + + def "The xcode archive should be called with the right configuration"() { + when: + subject.archive() + + then: + noExceptionThrown() + + 1 * mockCommandRunner.run([EXECUTABLE, + ACTION_ARCHIVE, + ARGUMENT_SCHEME, TEST_SCHEME, + ARGUMENT_ARCHIVE_PATH, outputDir.absolutePath, + ARGUMENT_XCCONFIG, fakeXccConfig.absolutePath], _) + } +} From 08f7fe5998d42acca8163fe3768b47d62ad009ea Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 11:42:05 +0100 Subject: [PATCH 089/121] Add unit test around the xcode version specification --- ...XcodeBuildArchiveTaskIosAndTvOSTest.groovy | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy b/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy index 74ff6234..588f0a67 100644 --- a/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy +++ b/plugin/src/test/groovy/org/openbakery/archiving/XcodeBuildArchiveTaskIosAndTvOSTest.groovy @@ -71,4 +71,44 @@ class XcodeBuildArchiveTaskIosAndTvOSTest extends Specification { ARGUMENT_ARCHIVE_PATH, outputDir.absolutePath, ARGUMENT_XCCONFIG, fakeXccConfig.absolutePath], _) } + + def "Should be able to customise xcode version"() { + when: + mockXcodeApp.contentDeveloperFile >> fakeXcodeRuntime + mockXcodeService.getInstallationForVersion(version) >> mockXcodeApp + + subject.xcodeVersion.set(version) + subject.archive() + + then: + noExceptionThrown() + + 1 * mockCommandRunner.run([EXECUTABLE, + ACTION_ARCHIVE, + ARGUMENT_SCHEME, TEST_SCHEME, + ARGUMENT_ARCHIVE_PATH, outputDir.absolutePath, + ARGUMENT_XCCONFIG, fakeXccConfig.absolutePath], + ['DEVELOPER_DIR': fakeXcodeRuntime.absolutePath.toString()]) + + where: + version | envValues + "9.3" | _ + "9.2" | _ + } + + def "The xcode version configuration should be optional"() { + when: + mockXcodeApp.contentDeveloperFile >> fakeXcodeRuntime + subject.xcodeVersion.set(null) + subject.archive() + + then: + noExceptionThrown() + + 1 * mockCommandRunner.run([EXECUTABLE, + ACTION_ARCHIVE, + ARGUMENT_SCHEME, TEST_SCHEME, + ARGUMENT_ARCHIVE_PATH, outputDir.absolutePath, + ARGUMENT_XCCONFIG, fakeXccConfig.absolutePath], [:]) + } } From 83d66756ef279fb8e00081a1fc6144f3df01d68c Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 14:57:49 +0100 Subject: [PATCH 090/121] Work in progress --- .../PrepareXcodeArchivingTask.groovy | 2 +- .../groovy/org/openbakery/XcodePlugin.groovy | 11 ++- .../packaging/PackageTaskIosAndTvOS.groovy | 30 ++++---- .../signing/ProvisioningFile.groovy | 57 +++++++++++++++ .../signing/ProvisioningInstallTask.groovy | 73 +++++++++++-------- .../org/openbakery/signing/Signing.groovy | 3 + 6 files changed, 127 insertions(+), 49 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index 768951d0..dc6692dc 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -88,7 +88,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { @TaskAction void generate() { - logger.lifecycle("Preparing archiving") + logger.debug("Preparing archiving") outputFile.get().asFile.text = "" diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index c4edf50e..a1cfaaea 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -591,10 +591,14 @@ class XcodePlugin implements Plugin { it.plistHelperProperty.set(plistHelper) it.plistHelperProperty.set(plistHelper) - // We use the result of the task to populate the read only value + // We use the result of the task to populate the read only values xcodeBuildPluginExtension.signing .registeredProvisioningFiles .set(it.registeredProvisioning) + + xcodeBuildPluginExtension.signing + .registeredProvisioning + .set(it.registeredProvisioningFiles) } project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) } @@ -627,8 +631,11 @@ class XcodePlugin implements Plugin { project.tasks.create(PackageTaskIosAndTvOS.NAME, PackageTaskIosAndTvOS) { it.group = XCODE_GROUP_NAME - it.signingMethod.set(xcodeBuildPluginExtension.signing.signingMethod) + it.buildType.set(xcodeBuildPluginExtension.type) + it.certificateFriendlyName.set(xcodeBuildPluginExtension.signing.certificateFriendlyName) + it.registeredProvisioningFiles.set(xcodeBuildPluginExtension.signing.registeredProvisioning) it.scheme.set(xcodeBuildPluginExtension.scheme) + it.signingMethod.set(xcodeBuildPluginExtension.signing.signingMethod) } } diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 406692fc..ee270f7e 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -1,7 +1,9 @@ package org.openbakery.packaging import groovy.transform.CompileStatic +import groovy.transform.TypeCheckingMode import org.gradle.api.Task +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec @@ -10,6 +12,7 @@ import org.openbakery.AbstractXcodeBuildTask import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask +import org.openbakery.signing.ProvisioningFile import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper @@ -25,8 +28,14 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input final Provider scheme = project.objects.property(String) -// @Input -// public final Provider targetType = project.objects.property(Type) + @Input + final Provider buildType = project.objects.property(Type) + + @Input + final ListProperty registeredProvisioningFiles = project.objects.listProperty(ProvisioningFile) + + @Input + final Property certificateFriendlyName = project.objects.property(String) private ProvisioningProfileReader reader @@ -95,12 +104,10 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { } @Input + @CompileStatic(TypeCheckingMode.SKIP) Map getProvisioningMap() { - setupProvisioningProfileReader() - - HashMap map = new HashMap<>() - map.put(reader.getApplicationIdentifier(), reader.getName()) - return map + return registeredProvisioningFiles.get() + .collectEntries { [it.getApplicationIdentifier(), it.getName()] } } @InputDirectory @@ -127,13 +134,6 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { packageIt() } - private void setupProvisioningProfileReader() { - if (reader == null) { - reader = new ProvisioningProfileReader(getProvisioningFile(), - commandRunner) - } - } - private void generateExportOptionPlist() { File file = getExportOptionsPlistFile() @@ -150,7 +150,7 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { // Certificate name addStringValueForPlist(PLIST_KEY_SIGNING_CERTIFICATE, - getSignatureFriendlyName()) + certificateFriendlyName.get()) // BitCode plistHelper.addValueForPlist(file, diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy new file mode 100644 index 00000000..3eee6b1c --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy @@ -0,0 +1,57 @@ +package org.openbakery.signing + +import org.apache.commons.io.FilenameUtils + +class ProvisioningFile implements Serializable { + + private File file + private String applicationIdentifier + private String uuid + private String teamIdentifier + private String teamName + private String name + + public static final String PROVISIONING_NAME_BASE = "gradle-" + + ProvisioningFile(File file, + String applicationIdentifier, + String uuid, + String teamIdentifier, + String teamName, + String name) { + this.applicationIdentifier = applicationIdentifier + this.file = file + this.uuid = uuid + this.teamIdentifier = teamIdentifier + this.teamName = teamName + this.name = name + } + + String getApplicationIdentifier() { + return applicationIdentifier + } + + File getFile() { + return file + } + + String getUuid() { + return uuid + } + + String getTeamIdentifier() { + return teamIdentifier + } + + String getTeamName() { + return teamName + } + + String getName() { + return name + } + + String getFormattedName() { + 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 af0a656b..7d2d65cb 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -24,6 +24,8 @@ class ProvisioningInstallTask extends Download { @OutputFiles final ListProperty registeredProvisioning = project.objects.listProperty(File) + final ListProperty registeredProvisioningFiles = project.objects.listProperty(ProvisioningFile) + final Property commandRunnerProperty = project.objects.property(CommandRunner) final Property plistHelperProperty = project.objects.property(PlistHelper) final Provider outputDirectory = project.layout.directoryProperty() @@ -48,6 +50,7 @@ class ProvisioningInstallTask extends Download { outputDirectory.get().asFile.mkdirs() configureDownload() super.download() + deleteFilesOnExit(getOutputFiles()) postDownload() } @@ -57,52 +60,60 @@ class ProvisioningInstallTask extends Download { this.acceptAnyCertificate(true) } - private void postDownload() { - final List files = rename() - deleteFilesOnExit(files) + void registerProvisioning(ProvisioningFile provisioningFile) { + registeredProvisioning.add(provisioningFile.getFile()) + registeredProvisioningFiles.add(provisioningFile) + } - final List libraryFiles = files.each { registeredProvisioning.add(it) } - .collect { linkToUserlibraryOfProvisioning(it) } + File registerProvisioningInToUserLibrary(ProvisioningFile provisioningFile) { + PROVISIONING_DIR.mkdirs() - deleteFilesOnExit(libraryFiles) + File destinationFile = new File(PROVISIONING_DIR, provisioningFile.getFormattedName()) + FileUtils.copyFile(provisioningFile.getFile(), destinationFile) + return destinationFile } - private List rename() { - return mobileProvisioningList.get() - .collect { new File(outputDirectory.get().asFile, FilenameUtils.getName(it)) } - .collect { return renameProvisioningFile(it) } - } + private void postDownload() { + // For convenience we rename the mobile provisioning file in to a formatted name + List files = rename() - private void deleteFilesOnExit(final List files) { - project.gradle.buildFinished { - files.each { - logger.debug("Delete file : " + it.absolutePath) - it.delete() - } - } + // Register it + files.each(this.®isterProvisioning) + + // Register into the user library + List registeredFiles = files.collect(this.®isterProvisioningInToUserLibrary) + deleteFilesOnExit(registeredFiles) } - private File renameProvisioningFile(File file) { - assert file.exists(): "Cannot rename a non existing file" + File fileFromPath(String path) { + return new File(outputDirectory.get().asFile, FilenameUtils.getName(path)) + } + ProvisioningFile toProvisioningFile(File file) { ProvisioningProfileReader reader = new ProvisioningProfileReader(file, commandRunnerProperty.get(), plistHelperProperty.get()) - String fileName = PROVISIONING_NAME_BASE + reader.getUUID() + "." + FilenameUtils.getExtension(file.getName()) + return new ProvisioningFile(file, + reader.getApplicationIdentifier(), + reader.getUUID(), + reader.getTeamIdentifierPrefix(), + reader.getTeamName(), + reader.getName()) + } - File result = new File(outputDirectory.get().asFile, fileName) - assert file.renameTo(result): "Failed to rename the provisioning file" - return result + private List rename() { + return mobileProvisioningList.get() + .collect(this.&fileFromPath) + .collect(this.&toProvisioningFile) } - private File linkToUserlibraryOfProvisioning(File file) { - if (!PROVISIONING_DIR.exists()) { - PROVISIONING_DIR.mkdirs() + private void deleteFilesOnExit(final List files) { + project.gradle.buildFinished { + files.each { + logger.debug("Delete file : " + it.absolutePath) + it.delete() + } } - - File destinationFile = new File(PROVISIONING_DIR, file.name) - FileUtils.copyFile(file, destinationFile) - return destinationFile } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy index 050a67c3..070a9ccb 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy @@ -34,6 +34,9 @@ class Signing { @Internal final Provider> registeredProvisioningFiles = project.objects.listProperty(File) + @Internal + final Provider> registeredProvisioning = project.objects.listProperty(ProvisioningFile) + @Internal Object keychainPathInternal From 5b347a5955ef9f35bea9d0655426e0fc5d4d098b Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 15:25:12 +0100 Subject: [PATCH 091/121] Packaging task adjustements --- .../org/openbakery/xcode/Xcodebuild.groovy | 7 +- .../XcodeBuildPluginExtension.groovy | 8 +- .../groovy/org/openbakery/XcodePlugin.groovy | 4 + .../packaging/PackageTaskIosAndTvOS.groovy | 89 ++++++++----------- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index c325eca5..48a4d2a7 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -47,9 +47,10 @@ class Xcodebuild { } } - public void packageIpa(File archivePath, - File exportPath, - File exportOptionsPlist) { + public static void packageIpa(CommandRunner commandRunner, + File archivePath, + File exportPath, + File exportOptionsPlist) { assert archivePath != null && archivePath.exists() assert exportPath != null && exportPath.exists() diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 501f720c..36cbed97 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory class XcodeBuildPluginExtension { public final static KEYCHAIN_NAME_BASE = "gradle-" + final Property bitcode final Property version final Property scheme final DirectoryProperty archiveDirectory @@ -73,8 +74,6 @@ class XcodeBuildPluginExtension { String ipaFileName = null File projectFile - Boolean bitcode = false - boolean useXcodebuildArchive = false @@ -98,7 +97,8 @@ class XcodeBuildPluginExtension { commandRunner = new CommandRunner() plistHelper = new PlistHelper(commandRunner) - this.project = project; + this.project = project + this.bitcode = project.objects.property(Boolean) this.version = project.objects.property(String) this.scheme = project.objects.property(String) @@ -504,7 +504,7 @@ class XcodeBuildPluginExtension { result.additionalParameters = this.additionalParameters result.devices = this.devices result.configuredDestinations = this.destinations - result.bitcode = this.bitcode + result.bitcode = this.bitcode.get() result.applicationBundle = getApplicationBundle() if (this.arch != null) { diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index a1cfaaea..b97dae29 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -631,8 +631,12 @@ class XcodePlugin implements Plugin { project.tasks.create(PackageTaskIosAndTvOS.NAME, PackageTaskIosAndTvOS) { it.group = XCODE_GROUP_NAME + + it.bitCode.set(xcodeBuildPluginExtension.bitcode) it.buildType.set(xcodeBuildPluginExtension.type) it.certificateFriendlyName.set(xcodeBuildPluginExtension.signing.certificateFriendlyName) + it.commandRunner.set(xcodeBuildPluginExtension.commandRunner) + it.plistHelper.set(xcodeBuildPluginExtension.plistHelper) it.registeredProvisioningFiles.set(xcodeBuildPluginExtension.signing.registeredProvisioning) it.scheme.set(xcodeBuildPluginExtension.scheme) it.signingMethod.set(xcodeBuildPluginExtension.signing.signingMethod) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index ee270f7e..bfa3eb05 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -2,13 +2,14 @@ package org.openbakery.packaging import groovy.transform.CompileStatic import groovy.transform.TypeCheckingMode +import org.gradle.api.DefaultTask import org.gradle.api.Task import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.specs.Spec import org.gradle.api.tasks.* -import org.openbakery.AbstractXcodeBuildTask +import org.openbakery.CommandRunner import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask @@ -16,11 +17,12 @@ import org.openbakery.signing.ProvisioningFile import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper +import org.openbakery.util.PlistHelper import org.openbakery.xcode.Type import org.openbakery.xcode.Xcodebuild @CompileStatic -class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { +class PackageTaskIosAndTvOS extends DefaultTask { @Input public final Property signingMethod = project.objects.property(SigningMethod) @@ -37,6 +39,12 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { @Input final Property certificateFriendlyName = project.objects.property(String) + @Input + final Provider bitCode = project.objects.property(Boolean) + + final Provider commandRunner = project.objects.property(CommandRunner) + final Provider plistHelper = project.objects.property(PlistHelper) + private ProvisioningProfileReader reader public static final String DESCRIPTION = "Package the archive with Xcode-build" @@ -64,45 +72,12 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { - return getXcodeExtension().getType() == Type.iOS || - getXcodeExtension().getType() == Type.tvOS + return buildType.get() == Type.iOS || + buildType.get() == Type.tvOS } }) } - @Override - File getProvisioningFile() { - return super.getProvisioningFile() - } - - @Input - boolean getBitCode() { - boolean result = getXcodeExtension().bitcode - SigningMethod method = signingMethod.get() - - if (method == SigningMethod.AppStore - && getXcodeExtension().type == Type.tvOS) { - assert result: "Invalid configuration for the TvOS target " + - "`AppStore` upload requires BitCode enabled." - } else if (method != SigningMethod.AppStore) { - assert !result: "The BitCode setting (`xcodebuild.bitcode`) should be enabled only " + - "for the `AppStore` signing method" - } - - return result - } - - @Input - String getBundleIdentifier() { - return super.getBundleIdentifier() - } - - @Input - @Override - String getSignatureFriendlyName() { - return super.getSignatureFriendlyName() - } - @Input @CompileStatic(TypeCheckingMode.SKIP) Map getProvisioningMap() { @@ -134,17 +109,34 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { packageIt() } + private boolean validateBitCodeSettings() { + Boolean bitCodeValue = bitCode.get() + SigningMethod method = signingMethod.get() + + if (method == SigningMethod.AppStore) { + if (buildType.get() == Type.tvOS) { + assert bitCodeValue: "Invalid configuration for the TvOS target " + + "`AppStore` upload requires BitCode enabled." + } + } else { + assert !bitCodeValue: "The BitCode setting (`xcodebuild.bitCode`) should be " + + "enabled only for the `AppStore` signing method" + } + + return bitCodeValue + } + private void generateExportOptionPlist() { File file = getExportOptionsPlistFile() - plistHelper.create(file) + plistHelper.get().create(file) // Signing method addStringValueForPlist(PLIST_KEY_METHOD, signingMethod.get().value) // Provisioning profiles map list - plistHelper.addDictForPlist(file, + plistHelper.get().addDictForPlist(file, PLIST_KEY_PROVISIONING_PROFILE, getProvisioningMap()) @@ -153,9 +145,9 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { certificateFriendlyName.get()) // BitCode - plistHelper.addValueForPlist(file, + plistHelper.get().addValueForPlist(file, PLIST_KEY_COMPILE_BITCODE, - getBitCode()) + validateBitCodeSettings()) // SigningMethod addStringValueForPlist(PLIST_KEY_SIGNING_STYLE, @@ -167,20 +159,15 @@ class PackageTaskIosAndTvOS extends AbstractXcodeBuildTask { assert key != null assert value != null - plistHelper.addValueForPlist(getExportOptionsPlistFile(), - key, - value) + plistHelper.get() + .addValueForPlist(getExportOptionsPlistFile(), key, value) } private void packageIt() { - Xcodebuild xcodeBuild = new Xcodebuild(project.projectDir, - commandRunner, - xcode, - parameters, - getDestinations()) - - xcodeBuild.packageIpa(getArchiveFile(), + Xcodebuild.packageIpa(commandRunner.get(), + getArchiveFile(), getOutputDirectory(), getExportOptionsPlistFile()) } + } From 2af7cda1ff3b3c6aca953bd5c33032522b0acd4a Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 15:27:03 +0100 Subject: [PATCH 092/121] Clearning up --- .../org/openbakery/packaging/PackageTaskIosAndTvOS.groovy | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index bfa3eb05..c54ce4a5 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -11,7 +11,6 @@ import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.CommandRunner import org.openbakery.XcodePlugin -import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningFile import org.openbakery.signing.ProvisioningInstallTask @@ -45,8 +44,6 @@ class PackageTaskIosAndTvOS extends DefaultTask { final Provider commandRunner = project.objects.property(CommandRunner) final Provider plistHelper = project.objects.property(PlistHelper) - private ProvisioningProfileReader reader - public static final String DESCRIPTION = "Package the archive with Xcode-build" public static final String NAME = "packageWithXcodeBuild" From 49ec4119f9cd7d590db68a980d926ea5b0fb01a6 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 15 May 2018 16:26:00 +0100 Subject: [PATCH 093/121] Start to put extension related classes to specific package --- .../groovy/org/openbakery/XcodeBuildPluginExtension.groovy | 2 +- .../org/openbakery/{signing => extension}/Signing.groovy | 4 +++- .../groovy/org/openbakery/signing/KeychainCreateTask.groovy | 1 + .../org/openbakery/PrepareXcodeArchivingTaskTest.groovy | 2 +- .../groovy/org/openbakery/signing/SigningSpecification.groovy | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) rename plugin/src/main/groovy/org/openbakery/{signing => extension}/Signing.groovy (97%) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 36cbed97..40bdcf59 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -23,7 +23,7 @@ import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil -import org.openbakery.signing.Signing +import org.openbakery.extension.Signing import org.openbakery.util.PathHelper import org.openbakery.util.PlistHelper import org.openbakery.util.VariableResolver diff --git a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy similarity index 97% rename from plugin/src/main/groovy/org/openbakery/signing/Signing.groovy rename to plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 070a9ccb..dda98036 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -1,4 +1,4 @@ -package org.openbakery.signing +package org.openbakery.extension import org.gradle.api.Project import org.gradle.api.Transformer @@ -11,6 +11,8 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.Internal 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 diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 06633cac..fdde0029 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -7,6 +7,7 @@ import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.TaskAction import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.extension.Signing import org.openbakery.util.FileUtil import org.openbakery.util.SystemUtil import org.openbakery.xcode.Version diff --git a/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy index f4da596f..8efa86c0 100644 --- a/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy +++ b/plugin/src/test/groovy/org/openbakery/PrepareXcodeArchivingTaskTest.groovy @@ -5,7 +5,7 @@ import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.rules.TemporaryFolder import org.openbakery.codesign.ProvisioningProfileReader -import org.openbakery.signing.Signing +import org.openbakery.extension.Signing import org.openbakery.util.PlistHelper import spock.lang.Specification diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index 2376f5ad..aee9b92c 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -5,6 +5,7 @@ import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.codesign.CodesignParameters import org.openbakery.configuration.ConfigurationFromMap +import org.openbakery.extension.Signing import spock.lang.Specification import spock.lang.Unroll From f74ffd276b451a2ae7224ad5a89d21908d093161 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 16 May 2018 14:29:40 +0100 Subject: [PATCH 094/121] --wip-- [skip ci] --- errors.log | 128 ++++++++++++++++++ plugin/build.gradle | 11 +- .../org/openbakery/extension/Signing.groovy | 33 +++-- .../org/openbakery/util/SystemUtil.groovy | 22 +++ .../src/test/Resource/fake_distribution.p12 | Bin 0 -> 2709 bytes .../signing/SigningSpecification.groovy | 79 +++++++++-- 6 files changed, 252 insertions(+), 21 deletions(-) create mode 100644 errors.log create mode 100644 plugin/src/test/Resource/fake_distribution.p12 diff --git a/errors.log b/errors.log new file mode 100644 index 00000000..7ee1349d --- /dev/null +++ b/errors.log @@ -0,0 +1,128 @@ +DRAWING THE SCREEN +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +UNREADY! +UNREADY! +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +UNREADY! +TRYING TO SPAWN +TRYING TO SPAWN +SHOULD HAVE SPAWNED +SHOULD HAVE SPAWNED +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: C +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: C +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: D +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: D +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: D +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: D +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: B +ON KEY STROKE +CURRENT INPUT:  +ON KEY STROKE +CURRENT INPUT: [ +ON KEY STROKE +CURRENT INPUT: B +YOU LOSE +GAME ENDED! +DRAWING THE SCREEN +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set +TOP is set diff --git a/plugin/build.gradle b/plugin/build.gradle index 105832cf..1962fc10 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -59,8 +59,17 @@ task sourcesJar(type: Jar) { from project(":libxcode").sourceSets.main.allSource classifier = 'sources' } - +s sourceSets { + test { + groovy { + srcDir file('src/test/groovy') + } + resources { + srcDir file('src/test/Resource') + } + } + functionalTest { groovy { srcDir file('src/functionalTest/groovy') diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index dda98036..63a3ea96 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -21,17 +21,17 @@ import java.util.regex.Pattern class Signing { - final DirectoryProperty signingDestinationRoot = project.layout.directoryProperty() final DirectoryProperty provisioningDestinationRoot = project.layout.directoryProperty() - final Property certificatePassword - final Property certificateFriendlyName + final DirectoryProperty signingDestinationRoot = project.layout.directoryProperty() + final ListProperty mobileProvisionList = project.objects.listProperty(String) final Property timeout = project.objects.property(Integer) final Property signingMethod = project.objects.property(SigningMethod) + final Property certificateFriendlyName + final Property certificatePassword final RegularFileProperty certificate final RegularFileProperty entitlementsFile final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() - final ListProperty mobileProvisionList = project.objects.listProperty(String) @Internal final Provider> registeredProvisioningFiles = project.objects.listProperty(File) @@ -64,6 +64,7 @@ class Signing { @Inject Signing(Project project) { + this.project = project this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) @@ -85,8 +86,9 @@ class Signing { this.timeout.set(3600) this.xcConfigFile = project.layout.fileProperty() - this.xcConfigFile.set(project.layout.buildDirectory.file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) -// PathHelper.resolveXcConfigFile(project)) + this.xcConfigFile.set(project.layout.buildDirectory.file(PathHelper.FOLDER_ARCHIVE + + "/" + + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) } void setKeychain(Object keychain) { @@ -132,6 +134,12 @@ class Signing { certificate.set(new File(new URI(uri))) } + @Deprecated + void setEntitlementsFile(String value) { + println "new File(value) : " + new File(value) + entitlementsFile.set(new File(value)) + } + @Override public String toString() { if (this.keychain != null) { @@ -152,12 +160,15 @@ class Signing { CodesignParameters getCodesignParameters() { CodesignParameters result = new CodesignParameters() result.signingIdentity = getIdentity() - result.mobileProvisionFiles = registeredProvisioningFiles.getFiles().asList().clone() as List - result.keychain = getKeychain() - if (entitlements != null) { - result.entitlements = entitlements.clone() + if (registeredProvisioningFiles.present) { + result.mobileProvisionFiles = new ArrayList(registeredProvisioningFiles.get() + .asList() + .toArray() as ArrayList) } - result.entitlementsFile = getEntitlementsFile() + result.keychain = getKeychain().asFile.getOrNull() as File + result.signingIdentity = identity + result.entitlementsFile = entitlementsFile.asFile.getOrNull() + return result } diff --git a/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy index 642e745a..7b142d39 100644 --- a/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy +++ b/plugin/src/main/groovy/org/openbakery/util/SystemUtil.groovy @@ -18,4 +18,26 @@ class SystemUtil { } return result } + + public static boolean isValidUri(String value) { + boolean result = true + try { + new File(new URI(value)) + } catch (Exception exception) { + result = false + } + + return result + } + + public static boolean isValidUrl(String value) { + boolean result = true + try { + new File(new URL(value)) + } catch (Exception exception) { + result = false + } + + return result + } } diff --git a/plugin/src/test/Resource/fake_distribution.p12 b/plugin/src/test/Resource/fake_distribution.p12 new file mode 100644 index 0000000000000000000000000000000000000000..208b05e0ad22ba0057fe49cd81023911d46dbbce GIT binary patch literal 2709 zcmY+Ec|6n$7sh`xhGE8@ec!WY?6Qj}Axj8D*|&yaEJ>F8qmsOY(UiR!V{9p1*-Iiz z$SzmRwPjS6#+vm`_w&B*ecwOM=bZCA&pCg7Q6M4<3SmHj2p1+6#oOm@@32AOkP;Aa z4hAC3>9Pq5geCrCF_nNYEM2+=g#h&C_m2ZXi7+Al{ecz2gkpy=M=r$duDhFQL7~h* z5(v|6Rf9NmomM7t*V-XTF^0Pj&h5K->|>t5+h3x$Sdx1O3`b}@yuu~u`FU}-_PRp$;$Tp zL1sSco|BZoclB{yP?SSL%posa;bKs^CvWD!WY@IuDQW6xk=E-D+LCLVXywbQqx#y? zd5Yq+>(Z#wa=7k?v7)CrqUQ;nUE=NSUT5tPI=P?q_r46Dk>uRkbaEz&^jk!|N6wWU zw-$7GfAR4bY0Kwwp0dKnUQd_7os5?G$avuD#`jG@FlihN?#);_tx4Tzp*Y+MXhLuz z3P0NNl+uXo28NGs=Oz|c`^;GKI3>lVPgXE+C28zn%xXQ-6P)sP7llqepf$F_$agup`{qy$w!_d>SB${3JN`MMPaR{N zqkLVQ=WgVPM5#-+inK7KG;&ssk*>CUDhMhS7*8fQGF=d@=XMbIX0+rxko*Lk%^FU& zU)-u|#zmi4-u8q(U}0u1r0txPR$O5_dU~ofm0B$jXn{w|SzI5uc=o`_idE$E>cZ|E zd24O2c?oV44jG)qOA82>si!eOj~@YsdfVHVH;E%LT3cz?X1;-hVqKd=p*yMjtJQIY zVFBIuT7&VU=X~l}H$m#qOz__RDssjwUxXPYw2dcWee{w*nN8HUs za@Yd*^a4GQ?!)AAzc!095rWPx*Xrq*T~yR@;nIAr$Y#$`^kVO-;#k%Y(`U}GH(T8g zl&5Ntg>mijU(+;iW9rsfW|ah0U=+>hLd%B1I$QFKtO)WwD0xw&KKO8K9l%U|3P=o7sr~anFN^~^f$ODXc^LLJtg31(4Rtc)2;R_FZ2ECH|YEvpJ?K# z(T%X)JiR3dm0kHgZPKj7o)c@>T)q6=;tl&_r|MwnkGndLl*Js#3E6vG*rQRlM5TB~{B)irsx=%}WpwEV~qhcbYy7(=h8h+yr-;Xr*&?*xT4)uZG|*lbcmtDL}i8Yl3EKxVE^D zV?H7O{gKhq4gEYaX<80hMB00<2Z@;1;uIU+%t9jPeeowtm5=-dt!ol|wbwr)hNgmF z51&a@;EVL2jo-@Tun>=t0jnzmEW=THW6oihC2|9q9SmcKT4Zvz)Y>!Vzf!w-7(KgT z1QSt>6H*HT&r-6EPyTj@Ci_~-Y~rKUhoFkJ7$HgWUPPJbn15K>m;x1ka|-+T;dg-H zlt^SCCoDB0`=ZkOm4YX8;k5W^PQn%A5#@`yp_`WF%VzUBYaMyHsdcRrqdEwabD1(6 z(vzkmy!^!h-mzO#?S`I;eM^1m{SCudF+I2CPb%^#M%9O%-YshJ?*`-cm+W0`nM~RB zW({;ZJs+=l+0;!+_8J{OTIhV5-&RR!1?#Le&tzT}*YL^M_Nqci zU#mMef+%lT$kIWR8(54E@7ufm{Yo~XUZt}oK9*ymn{ah#jV$wOk- z7pU07pFlx#k8S2d29$P$Oi*idq&(QUYez;C>@p|IKJp-(_P@{V2GO&?oiwDiox^z9@lG zi`H_OYCMr4HR)k>eb1dO^c#eqk(y^9aHKE4Qe^<6k9AUy66sWp(^*J9lu8 zNX~7|!Gx6j!P_HBaZ%V`xHA<~%8X1Axy1X78pSdc8q(y9?@aFs6IKBur^zI_V;dIkU{dK#3?&m>peNbr2M3c$JA83Vo0wl>HgA z7*x3yo@~dvU~OGmUg$hSBBrmW8g_uV7ba^&^nQNqgiurGM=qg1qbZ5^7R8!jJrNWIyLBa#`}y7Fbs z&+u|e+-8&a!Whl@SBGUgC@LntCqA;mmv6Mov8MB`zf7ym$1%4tcKEXthq~a3zN}YvB|&w2cl-W_6vUhAjaqFe?~7`^+i|ZrRNr~3 zH=*;CHhYmjh@m=GmPYIx%)U73A1qA6_6aglq+JR9u}{AK95wdMl)F)`5kZ|B_dUaz zM9vrG{fRR$DE{{1L^66G9rA%&#f-_+18$(X#(I@ck_s4nb4HMr1GpG(RoTbj!sHnx z_o~%hiPAB`*BuAgEUlj{#i;#OfRg?%9$9$R_+UIoIf7Mv6K|_P0<>L=@M=IuHDlPw literal 0 HcmV?d00001 diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index aee9b92c..81fec5b0 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -3,6 +3,9 @@ package org.openbakery.signing import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.ExpectedException +import org.junit.rules.TemporaryFolder import org.openbakery.codesign.CodesignParameters import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.extension.Signing @@ -15,17 +18,22 @@ class SigningSpecification extends Specification { Project project File projectDir + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + @Rule + public ExpectedException exception = ExpectedException.none() def setup() { - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") + projectDir = testProjectDir.root project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.buildDir = new File(projectDir, 'build').absoluteFile project.apply plugin: org.openbakery.XcodePlugin + signing = new Signing(project) } - def cleanup() { projectDir.delete() } @@ -44,7 +52,7 @@ class SigningSpecification extends Specification { then: noExceptionThrown() - signing.getMethod() == method + signing.signingMethod.get() == method where: string | method @@ -68,6 +76,27 @@ class SigningSpecification extends Specification { null | _ } + def "The XcConfig file path can be configured and is by default buildDir dependant"() { + when: + File file = signing.xcConfigFile.asFile.get() + + then: + noExceptionThrown() + file.absoluteFile == new File(project.buildDir, "archive/archive.xcconfig") + + when: + File altBuildDir = testProjectDir.newFolder("build-dir-alt") + assert project.buildDir != altBuildDir + project.buildDir = altBuildDir + + and: + File file2 = signing.xcConfigFile.asFile.get() + + then: + noExceptionThrown() + file2.absoluteFile == new File(altBuildDir, "archive/archive.xcconfig") + } + def "entitlements data set via closure using xcodebuild"() { when: @@ -78,7 +107,6 @@ class SigningSpecification extends Specification { then: project.xcodebuild.signing.entitlements instanceof Map project.xcodebuild.signing.entitlements.containsKey("com.apple.security.application-groups") - } def "entitlements data set via closure"() { @@ -114,6 +142,7 @@ class SigningSpecification extends Specification { def "codesignParameters has identity"() { when: signing.identity = "Me" + then: signing.codesignParameters.signingIdentity == "Me" } @@ -150,25 +179,57 @@ class SigningSpecification extends Specification { } def "codesignParameters has entitlementsFile"() { + setup: + File entitlementsFile = testProjectDir.newFile("test.entitlements") + when: - signing.entitlementsFile = new File("entitlements") + signing.entitlementsFile = entitlementsFile + then: - signing.codesignParameters.entitlementsFile == new File("entitlements") + signing.codesignParameters.entitlementsFile == entitlementsFile } + def "When defining the certificate the friendlyName should be updated"() { + setup: + File cert = new File("src/test/Resource/fake_distribution.p12") + signing.certificate.set(cert.absoluteFile) + + when: "If not password is defined, should trow an exeption" + signing.certificateFriendlyName.get() + + then: + thrown IllegalStateException.class + + when: "Defining password" + signing.certificatePassword.set("p4ssword") + + and: + signing.certificateFriendlyName.get() == "iPhone Distribution: Test Company Name (12345ABCDE)" + + then: + noExceptionThrown() + } def "codesignParameter entitlementsFile as String"() { when: - signing.entitlementsFile = "entitlements" + signing.entitlementsFile = "entitlements/test.entitlements" + then: - signing.codesignParameters.entitlementsFile instanceof File - signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") + noExceptionThrown() + with(signing.entitlementsFile + .get() + .asFile) { + name == "test.entitlements" + parent.endsWith("/entitlements") + } } def "codesignParameter entitlementsFile as String full path"() { when: signing.entitlementsFile = "file:///entitlements" + then: + noExceptionThrown() signing.codesignParameters.entitlementsFile instanceof File signing.codesignParameters.entitlementsFile.path.endsWith("entitlements") } From 8cedf312a8a5d75076fc3cafa4ae531b55205563 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 14:40:06 +0100 Subject: [PATCH 095/121] Fix the infoplist unit test --- plugin/build.gradle | 2 +- .../main/groovy/org/openbakery/InfoPlistModifyTask.groovy | 6 +++--- .../groovy/org/openbakery/XcodeBuildPluginExtension.groovy | 1 - .../org/openbakery/InfoPlistModifyTaskSpecification.groovy | 7 ------- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index 1962fc10..83cac330 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -59,7 +59,7 @@ task sourcesJar(type: Jar) { from project(":libxcode").sourceSets.main.allSource classifier = 'sources' } -s + sourceSets { test { groovy { diff --git a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy index 57523198..51b972a5 100644 --- a/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/InfoPlistModifyTask.groovy @@ -140,14 +140,14 @@ class InfoPlistModifyTask extends AbstractDistributeTask { } private void modifyBundleIdentifier() { + // Resolve bundle identifier + XcodeBuildPluginExtension xcodeExtension = getXcodeExtension() InfoPlistExtension extension = getInfoPlistExtension() - // Resolve bundle identifier if (extension.bundleIdentifier != null) { setValueForPlist(KeyBundleIdentifier, extension.bundleIdentifier) } else { - XcodeBuildPluginExtension xcodeExtension = getXcodeExtension() - xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme.get(), + xcodeExtension.getBuildTargetConfiguration(xcodeExtension.scheme.getOrNull(), xcodeExtension.configuration) .map { it -> it.bundleIdentifier } .ifPresent { it -> setValueForPlist(KeyBundleIdentifier, it) } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 40bdcf59..cd7b86d2 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -434,7 +434,6 @@ class XcodeBuildPluginExtension { return result } - void setType(String type) { this.type = Type.typeFromString(type) } diff --git a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy index 51f89c58..a580c9ae 100644 --- a/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/InfoPlistModifyTaskSpecification.groovy @@ -19,15 +19,12 @@ class InfoPlistModifyTaskSpecification extends Specification { CommandRunner commandRunner = Mock(CommandRunner) def setup() { - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.apply plugin: org.openbakery.XcodePlugin - projectDir.mkdirs() - project.xcodebuild.infoPlist = "App-Info.plist" task = project.tasks.findByName('infoplistModify') @@ -36,8 +33,6 @@ class InfoPlistModifyTaskSpecification extends Specification { infoPlist = new File(task.project.projectDir, "App-Info.plist") FileUtils.writeStringToFile(infoPlist, "dummy") - - } def cleanup() { @@ -111,7 +106,6 @@ class InfoPlistModifyTaskSpecification extends Specification { then: plistHelper.plistCommands[0] == "Add CFBundleURLTypes:0:CFBundleURLName string" - } def "modify command multiple"() { @@ -146,7 +140,6 @@ class InfoPlistModifyTaskSpecification extends Specification { then: plistHelper.getValueFromPlist(infoPlist, "CFBundleShortVersionString") == "1.2.3" - } def "nothing to modify"() { From a0f180058578d2df0550efd4ca750bb63dd4b23e Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 14:47:01 +0100 Subject: [PATCH 096/121] Fix the libxcode tests --- libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy | 5 +++-- .../groovy/org/openbakery/xcode/XcodeSpecification.groovy | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index ca26a525..89f80ad2 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -63,8 +63,6 @@ class Xcode { } void setVersionFromString(String version) throws IllegalArgumentException { - assert version != null - Optional result = resolveXcodeInstallOfVersion(version) if (result.isPresent()) { @@ -75,6 +73,9 @@ class Xcode { } Optional resolveXcodeInstallOfVersion(String version) { + if (version == null) + return Optional.empty() + final Version requiredVersion = new Version(version) return Optional.ofNullable(resolveInstalledXcodeVersionsList() diff --git a/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy b/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy index 08123b4d..41e4342d 100644 --- a/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy +++ b/libxcode/src/test/groovy/org/openbakery/xcode/XcodeSpecification.groovy @@ -229,7 +229,7 @@ class XcodeSpecification extends Specification { "5.1.3" | IllegalStateException "10.0" | IllegalStateException "7.1.3" | IllegalStateException - null | IllegalArgumentException + null | IllegalStateException } def "Should return a map of environment values containing the developer dir key for valid xcode version"() { From 606a7ca7925f64a83c398d9bc1e2933cd9b95286 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 14:51:41 +0100 Subject: [PATCH 097/121] Fix the ProvisioningProfileReaderSpecification unit tests --- ...visioningProfileReaderSpecification.groovy | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy index 13db20a7..d80285f4 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy @@ -38,7 +38,7 @@ class ProvisioningProfileReaderSpecification extends Specification { project.xcodebuild.productName = 'Example' project.xcodebuild.productType = 'app' project.xcodebuild.type = Type.macOS - project.xcodebuild.signing.keychain = "/var/tmp/gradle.keychain" + project.xcodebuild.signing.keychain.set(project.file("/var/tmp/gradle.keychain")) packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) @@ -83,7 +83,7 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "profile has expired" () { + def "profile has expired"() { when: new ProvisioningProfileReader(new File("src/test/Resource/expired.mobileprovision"), new CommandRunner()) @@ -112,11 +112,11 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReaderIgnoreExpired(provisioningProfile, commandRunner, new PlistHelper(new CommandRunner())) commandRunner.runWithResult([ - "/usr/libexec/PlistBuddy", - "-x", - provisioningProfile.absolutePath, - "-c", - "Print Entitlements"]) >> null + "/usr/libexec/PlistBuddy", + "-x", + provisioningProfile.absolutePath, + "-c", + "Print Entitlements"]) >> null File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -286,25 +286,25 @@ class ProvisioningProfileReaderSpecification extends Specification { String getEntitlementWithApplicationIdentifier(String applicationIdentifier) { return "\n" + - "\n" + - "\n" + - "\n" + - " keychain-access-groups\n" + - " \n" + - " AAAAAAAAAA.*\n" + - " \n" + - " get-task-allow\n" + - " \n" + - " application-identifier\n" + - " " + applicationIdentifier + "\n" + - " com.apple.developer.team-identifier\n" + - " AAAAAAAAAA\n" + - " com.apple.developer.ubiquity-kvstore-identifier\n" + - " ABCDE12345.*\n" + - " com.apple.developer.ubiquity-container-identifiers\n" + - " ABCDE12345.*\n" + - "\n" + - "" + "\n" + + "\n" + + "\n" + + " keychain-access-groups\n" + + " \n" + + " AAAAAAAAAA.*\n" + + " \n" + + " get-task-allow\n" + + " \n" + + " application-identifier\n" + + " " + applicationIdentifier + "\n" + + " com.apple.developer.team-identifier\n" + + " AAAAAAAAAA\n" + + " com.apple.developer.ubiquity-kvstore-identifier\n" + + " ABCDE12345.*\n" + + " com.apple.developer.ubiquity-container-identifiers\n" + + " ABCDE12345.*\n" + + "\n" + + "" } def "extract Entitlements with wildcard application identifier that does not match"() { @@ -317,7 +317,7 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileprovision, commandRunner) def keychainAccessGroups = [ - ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", + ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", ] File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -338,7 +338,7 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileprovision, commandRunner, new PlistHelper(new CommandRunner())) def keychainAccessGroups = [ - ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", + ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", ] File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -352,7 +352,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "extract Entitlements with wildcard application identifier that does match"() { given: File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -363,7 +362,7 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileprovision, commandRunner, new PlistHelper(new CommandRunner())) def keychainAccessGroups = [ - ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", + ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", ] File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -403,7 +402,7 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileprovision, commandRunner, new PlistHelper(new CommandRunner())) def keychainAccessGroups = [ - ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", + ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", ] File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -424,7 +423,7 @@ class ProvisioningProfileReaderSpecification extends Specification { ProvisioningProfileReader reader = new ProvisioningProfileReader(mobileprovision, commandRunner, new PlistHelper(new CommandRunner())) def keychainAccessGroups = [ - ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", + ProvisioningProfileReader.APPLICATION_IDENTIFIER_PREFIX + "org.openbakery.test.Example", ] File entitlementsFile = new File(projectDir, "entitlements.plist") @@ -449,7 +448,7 @@ class ProvisioningProfileReaderSpecification extends Specification { then: 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security","cms","-D","-i", mobileprovision.absolutePath, "-o", expectedProvisioningPlist.absolutePath] + commandList == ["security", "cms", "-D", "-i", mobileprovision.absolutePath, "-o", expectedProvisioningPlist.absolutePath] } @@ -463,9 +462,9 @@ class ProvisioningProfileReaderSpecification extends Specification { when: def list = [ - appMobileprovision, - widgetMobileprovision, - wildcardMobileprovision + appMobileprovision, + widgetMobileprovision, + wildcardMobileprovision ] then: @@ -484,8 +483,8 @@ class ProvisioningProfileReaderSpecification extends Specification { when: def list = [ - appMobileprovision, - wildcardMobileprovision + appMobileprovision, + wildcardMobileprovision ] then: @@ -623,7 +622,7 @@ class ProvisioningProfileReaderSpecification extends Specification { def "extract Entitlements set keychain access group with configuration key and replace AppIdentiferPrefix variable"() { given: Map data = [ - "keychain-access-groups": [ "\$(AppIdentifierPrefix)com.example.Test" ] + "keychain-access-groups": ["\$(AppIdentifierPrefix)com.example.Test"] ] File entitlementsFile = setupForEntitlementTest(data) From 316ae17d04d3011458124c08a2232d457314452d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 14:52:47 +0100 Subject: [PATCH 098/121] Tweaks --- .../signing/ProvisioningProfileReaderSpecification.groovy | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy index d80285f4..12a84bc8 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy @@ -70,19 +70,19 @@ class ProvisioningProfileReaderSpecification extends Specification { def "read application identifier prefix"() { when: ProvisioningProfileReader reader = new ProvisioningProfileReader(new File("../libtest/src/main/Resource/test.mobileprovision"), new CommandRunner()) + then: reader.getApplicationIdentifierPrefix().equals("AAAAAAAAAAA") } - def "read application identifier"() { when: ProvisioningProfileReader reader = new ProvisioningProfileReader(new File("../libtest/src/main/Resource/test.mobileprovision"), new CommandRunner()) + then: reader.getApplicationIdentifier() == "org.openbakery.test.Example" } - def "profile has expired"() { when: new ProvisioningProfileReader(new File("src/test/Resource/expired.mobileprovision"), new CommandRunner()) @@ -618,7 +618,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlements.getString("com..apple..developer..icloud-services") == "com.example.test" } - def "extract Entitlements set keychain access group with configuration key and replace AppIdentiferPrefix variable"() { given: Map data = [ @@ -635,7 +634,5 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlements.getList("keychain-access-groups").contains("AAAAAAAAAAA.com.example.Test") } - - } From f80a961a7dc99c2c5c077aeeac6bb07569aaf61d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 15:23:26 +0100 Subject: [PATCH 099/121] Ajsutements in the signing spec --- .../org/openbakery/extension/Signing.groovy | 34 +++++------- .../signing/SigningSpecification.groovy | 52 ++++++++----------- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 63a3ea96..5ad4410f 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -45,6 +45,9 @@ class Signing { @Internal final RegularFileProperty xcConfigFile + @Deprecated + final Property> entitlementsMap + public static final String KEYCHAIN_NAME_BASE = "gradle-" private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ @@ -56,12 +59,9 @@ class Signing { * internal parameters */ private final Project project - private - final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" + private final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" CommandRunner commandRunner - List mobileProvisionFile = new ArrayList() - @Inject Signing(Project project) { @@ -80,6 +80,9 @@ class Signing { })) this.commandRunner = new CommandRunner() + + // Entitlements support + this.entitlementsMap = project.objects.property(Map) this.entitlementsFile = project.layout.fileProperty() this.keyChainFile.set(signingDestinationRoot.file(keychainName)) @@ -109,12 +112,12 @@ class Signing { return project.file(keychainPathInternal) } - void setMobileProvisionURI(List list) { - list.each { this.mobileProvisionList.add(it) } - } - - void setMobileProvisionURI(String value) { - this.mobileProvisionList.add(value) + public void entitlements(Map entitlements) { + if (!this.entitlementsMap.present) { + this.entitlementsMap.set(entitlements) + } else { + this.entitlementsMap.get() << entitlements + } } boolean hasEntitlementsFile() { @@ -125,18 +128,8 @@ class Signing { return this.identity } - public void entitlements(Map entitlements) { - this.entitlements = entitlements - - } - - void setCertificateURI(String uri) { - certificate.set(new File(new URI(uri))) - } - @Deprecated void setEntitlementsFile(String value) { - println "new File(value) : " + new File(value) entitlementsFile.set(new File(value)) } @@ -167,6 +160,7 @@ class Signing { } result.keychain = getKeychain().asFile.getOrNull() as File result.signingIdentity = identity + result.entitlements = entitlementsMap.getOrNull() result.entitlementsFile = entitlementsFile.asFile.getOrNull() return result diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index 81fec5b0..cbdd1f9a 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -1,11 +1,11 @@ package org.openbakery.signing -import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.rules.ExpectedException import org.junit.rules.TemporaryFolder +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.codesign.CodesignParameters import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.extension.Signing @@ -24,6 +24,8 @@ class SigningSpecification extends Specification { @Rule public ExpectedException exception = ExpectedException.none() + private Signing signingExtension + def setup() { projectDir = testProjectDir.root @@ -32,6 +34,10 @@ class SigningSpecification extends Specification { project.apply plugin: org.openbakery.XcodePlugin signing = new Signing(project) + + this.signingExtension = project.extensions + .findByType(XcodeBuildPluginExtension) + .signing } def cleanup() { @@ -100,35 +106,33 @@ class SigningSpecification extends Specification { def "entitlements data set via closure using xcodebuild"() { when: - project.xcodebuild.signing { - entitlements 'com.apple.security.application-groups': ['group.com.example.App'] - } + assert signingExtension != null + signingExtension.entitlements 'com.apple.security.application-groups': ['group.com.example.App'] then: - project.xcodebuild.signing.entitlements instanceof Map - project.xcodebuild.signing.entitlements.containsKey("com.apple.security.application-groups") + signingExtension.entitlementsMap.get() instanceof Map + signingExtension.entitlementsMap.get().containsKey("com.apple.security.application-groups") } def "entitlements data set via closure"() { when: - signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) + assert signingExtension != null + signingExtension.entitlements('com.apple.security.application-groups': ['group.com.example.App']) then: - signing.entitlements instanceof Map - signing.entitlements.containsKey("com.apple.security.application-groups") - signing.entitlements["com.apple.security.application-groups"] == ['group.com.example.App'] + signingExtension.entitlementsMap.get() instanceof Map + signingExtension.entitlementsMap.get().containsKey("com.apple.security.application-groups") + signingExtension.entitlementsMap.get()["com.apple.security.application-groups"] == ['group.com.example.App'] } - def "entitlements data set via closure converted to Configuration"() { when: signing.entitlements('com.apple.security.application-groups': ['group.com.example.App']) - def configuration = new ConfigurationFromMap(signing.entitlements) + def configuration = new ConfigurationFromMap(signing.entitlementsMap.get()) then: configuration.getStringArray("com.apple.security.application-groups") == ['group.com.example.App'] - } def "codesignParameters is not null"() { @@ -147,22 +151,6 @@ class SigningSpecification extends Specification { signing.codesignParameters.signingIdentity == "Me" } - def "codesignParameters has mobileProvisionFiles"() { - when: - - File first = new File(projectDir, "first") - FileUtils.write(first, "first") - File second = new File(projectDir, "second") - FileUtils.write(second, "second") - - signing.addMobileProvisionFile(first) - signing.addMobileProvisionFile(second) - - then: - signing.codesignParameters.mobileProvisionFiles instanceof List - signing.codesignParameters.mobileProvisionFiles == [first, second] - } - def "codesignParameters has keychain"() { when: signing.keychain = new File("my.keychain").absoluteFile @@ -173,7 +161,8 @@ class SigningSpecification extends Specification { def "codesignParameters has entitlements"() { when: - signing.entitlements = ['key': 'value'] + signing.entitlements(['key': 'value']) + then: signing.codesignParameters.entitlements == ['key': 'value'] } @@ -192,9 +181,10 @@ class SigningSpecification extends Specification { def "When defining the certificate the friendlyName should be updated"() { setup: File cert = new File("src/test/Resource/fake_distribution.p12") + assert cert.exists() signing.certificate.set(cert.absoluteFile) - when: "If not password is defined, should trow an exeption" + when: "If not password is defined, should trow an exception" signing.certificateFriendlyName.get() then: From 88f5b331188a5a6b8e339b637b16e4d9e1895039 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 17 May 2018 15:33:46 +0100 Subject: [PATCH 100/121] fix unit tests --- .../XcodeBuildPluginExtension.groovy | 4 ++-- .../KeychainCreateTaskSpecification.groovy | 5 +++-- .../DestinationResolverSpecification.groovy | 20 +++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index cd7b86d2..5b29a708 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -489,7 +489,7 @@ class XcodeBuildPluginExtension { XcodebuildParameters getXcodebuildParameters() { def result = new XcodebuildParameters() - result.scheme = this.scheme.get() + result.scheme = this.scheme.getOrNull() result.target = this.target result.simulator = this.simulator result.type = this.type @@ -503,7 +503,7 @@ class XcodeBuildPluginExtension { result.additionalParameters = this.additionalParameters result.devices = this.devices result.configuredDestinations = this.destinations - result.bitcode = this.bitcode.get() + result.bitcode = this.bitcode.getOrElse(false) result.applicationBundle = getApplicationBundle() if (this.arch != null) { diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy index 89917280..66290e0e 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy @@ -7,6 +7,7 @@ import org.junit.Rule import org.junit.rules.TemporaryFolder import org.openbakery.CommandRunner import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.XcodePlugin import org.openbakery.codesign.Security import org.openbakery.xcode.Type import spock.lang.Specification @@ -37,7 +38,7 @@ class KeychainCreateTaskSpecification extends Specification { def setup() { project = ProjectBuilder.builder().build() project.buildDir = new File('build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin + project.apply plugin: XcodePlugin mockSecurity = Mock(Security) @@ -71,7 +72,7 @@ class KeychainCreateTaskSpecification extends Specification { def "Mac OS #version - Temporary keychain should be create and certificate URI imported"() { given: System.setProperty("os.version", version) - project.xcodebuild.signing.certificateURI = certificateFile.toURL() + project.xcodebuild.signing.certificate = certificateFile when: keychainCreateTask.create() diff --git a/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy b/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy index 948d0704..e65a7bab 100644 --- a/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy @@ -2,13 +2,23 @@ package org.openbakery.xcode import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.ExpectedException +import org.junit.rules.TemporaryFolder import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.XcodePlugin import org.openbakery.simulators.SimulatorControl import org.openbakery.testdouble.SimulatorControlStub import spock.lang.Specification class DestinationResolverSpecification extends Specification { + @Rule + public ExpectedException exception = ExpectedException.none() + + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + Project project File projectDir XcodeBuildPluginExtension extension @@ -16,18 +26,14 @@ class DestinationResolverSpecification extends Specification { SimulatorControl simulatorControl def setup() { - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.apply plugin: org.openbakery.XcodePlugin + project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + project.apply plugin: XcodePlugin extension = new XcodeBuildPluginExtension(project) simulatorControl = new SimulatorControlStub("simctl-list-xcode7_1.txt") destinationResolver = new DestinationResolver(simulatorControl) } - - def "available destinations for OS X"() { - when: extension.type = Type.macOS @@ -35,7 +41,6 @@ class DestinationResolverSpecification extends Specification { destinationResolver.getDestinations(extension.getXcodebuildParameters()).size() == 1 } - def "XcodebuildParameters are created with iOS destination"() { when: Project project = ProjectBuilder.builder().build() @@ -136,7 +141,6 @@ class DestinationResolverSpecification extends Specification { } - def "available destinations match simple single"() { given: extension.destination = 'iPad Air' From 885be49eacbeb010ed66bfd57eeb5925ce7725a8 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 10:46:19 +0100 Subject: [PATCH 101/121] Cleaning up no more necessary classes --- .../org/openbakery/CommandRunner.groovy | 1 - .../org/openbakery/codesign/Security.groovy | 3 +- .../KeychainCreateTaskFunctionalTest.groovy | 12 +- ...PrepareXcodeArchivingFunctionalTest.groovy | 6 +- ...ovisioningInstallTaskFunctionalTest.groovy | 156 ++++++++++++++++++ .../org/openbakery/XcodeBuildCleanTask.groovy | 2 - .../groovy/org/openbakery/XcodePlugin.groovy | 24 --- .../org/openbakery/extension/Signing.groovy | 14 +- .../packaging/PackageLegacyTask.groovy | 7 +- .../packaging/PackageTaskIosAndTvOS.groovy | 2 - .../signing/AbstractKeychainTask.groovy | 54 ------ .../signing/KeychainCleanupTask.groovy | 38 ----- .../signing/KeychainCreateTask.groovy | 55 +++++- .../KeychainRemoveFromSearchListTask.groovy | 20 --- .../signing/ProvisioningCleanupTask.groovy | 54 ------ .../signing/ProvisioningFile.groovy | 4 + .../signing/ProvisioningInstallTask.groovy | 14 +- .../XcodeTestRunTaskSpecification.groovy | 14 -- ... => PackageLegacyTaskSpecification.groovy} | 12 +- .../KeychainCleanupTaskSpecification.groovy | 151 ----------------- ...moveFromSearchListTaskSpecification.groovy | 156 ------------------ ...rovisioningInstallTaskSpecification.groovy | 55 ++++-- 22 files changed, 284 insertions(+), 570 deletions(-) create mode 100644 plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy delete mode 100644 plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy delete mode 100644 plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy delete mode 100644 plugin/src/main/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTask.groovy delete mode 100644 plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy rename plugin/src/test/groovy/org/openbakery/packaging/{PackageTaskSpecification.groovy => PackageLegacyTaskSpecification.groovy} (97%) delete mode 100644 plugin/src/test/groovy/org/openbakery/signing/KeychainCleanupTaskSpecification.groovy delete mode 100644 plugin/src/test/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTaskSpecification.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index f49fc702..b52aeeff 100644 --- a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy +++ b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy @@ -38,7 +38,6 @@ class CommandRunner { } - void setOutputFile(File outputFile) { if (outputFile.exists()) { diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/Security.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/Security.groovy index 53034462..401ef292 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/Security.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/Security.groovy @@ -1,6 +1,5 @@ package org.openbakery.codesign -import org.apache.commons.io.FileUtils import org.apache.commons.io.FilenameUtils import org.apache.commons.lang.StringUtils import org.openbakery.CommandRunner @@ -9,7 +8,6 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.security.cert.CertificateException -import java.text.ParseException class Security { private static Logger logger = LoggerFactory.getLogger(Security.class) @@ -60,6 +58,7 @@ class Security { for (File keychain in keychainList) { commandList.add(keychain.absolutePath) } + commandRunner.run(commandList) } diff --git a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy index 266ba80b..c93801a1 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy @@ -75,7 +75,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.file("$certificate") + certificate = project.provisioningFile1("$certificate") } } """ @@ -96,7 +96,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.file("$certificate") + certificate = project.provisioningFile1("$certificate") certificatePassword = "p4ssword" } } @@ -118,7 +118,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.file("$certificate") + certificate = project.provisioningFile1("$certificate") certificatePassword = "p4ssword" } } @@ -134,21 +134,19 @@ class KeychainCreateTaskFunctionalTest extends Specification { then: result.task(":" + KeychainCreateTask.TASK_NAME).outcome == TaskOutcome.SUCCESS - and: "The temporary certificate file should be deleted automatically" + and: "The temporary certificate provisioningFile1 should be deleted automatically" new File(testProjectDir.root, "build/codesign") .listFiles() .toList() .findAll {it.name.endsWith(".p12")} .empty - and: "The temporary keychain file should be deleted automatically" + and: "The temporary keychain provisioningFile1 should be deleted automatically" new File(testProjectDir.root, "build/codesign") .listFiles() .toList() .findAll {it.name.endsWith(".keychain")} .empty - - println result.output } private File findResource(String name) { diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy index b5d09833..44ad243c 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -107,7 +107,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { result.task(":" + PrepareXcodeArchivingTask.NAME) .outcome == TaskOutcome.SUCCESS - and: "The archive xcconfig file should be properly generated and populated from configured values" + and: "The archive xcconfig provisioningFile1 should be properly generated and populated from configured values" File outputFile = new File(testProjectDir.root, "build/" + PathHelper.FOLDER_ARCHIVE @@ -154,7 +154,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { signing { certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" - entitlementsFile = project.file("${entitlementsFile.absolutePath}") + entitlementsFile = project.provisioningFile1("${entitlementsFile.absolutePath}") } } """ @@ -170,7 +170,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { result.task(":" + PrepareXcodeArchivingTask.NAME) .outcome == TaskOutcome.SUCCESS - and: "The archive xcconfig should contains the path to the entitlements file" + and: "The archive xcconfig should contains the path to the entitlements provisioningFile1" File outputFile = new File(testProjectDir.root, "build/" + PathHelper.FOLDER_ARCHIVE diff --git a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy new file mode 100644 index 00000000..d20157ff --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy @@ -0,0 +1,156 @@ +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 spock.lang.Unroll + +import java.nio.file.Paths + +class ProvisioningInstallTaskFunctionalTest extends Specification { + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + List pluginClasspath + + File buildFile + File provisioningFile1 + + def setup() { + buildFile = testProjectDir.newFile('build.gradle') + + buildFile << """ + plugins { + id 'org.openbakery.xcode-plugin' + } + """ + + 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') + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.output.contains(ProvisioningInstallTask.TASK_NAME + + " - " + + ProvisioningInstallTask.TASK_DESCRIPTION) + } + + def "If no provisioning is defined, then the task should be skipped"() { + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(ProvisioningInstallTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.task(":" + ProvisioningInstallTask.TASK_NAME) + .outcome == TaskOutcome.SKIPPED + } + + def "If provisioning list is empty, then the task should be skipped"() { + setup: + buildFile << """ + xcodebuild { + signing { + mobileProvisionURI = [] + } + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(ProvisioningInstallTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .build() + + then: + result.task(":" + ProvisioningInstallTask.TASK_NAME) + .outcome == TaskOutcome.SKIPPED + } + + def "The provisioning can be configured via the mobileProvisionList list"() { + setup: + buildFile << """ + xcodebuild { + signing { + mobileProvisionList = ["${provisioningFile1.toURI().toString()}"] + } + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(ProvisioningInstallTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .withDebug(true) + .build() + + then: + result.task(":" + ProvisioningInstallTask.TASK_NAME) + .outcome == TaskOutcome.SUCCESS + } + + @Unroll + def "With gradle version : #gradleVersion If provisioning list is present, then the task should be skipped"() { + setup: + buildFile << """ + xcodebuild { + signing { + mobileProvisionURI = "${provisioningFile1.toURI().toString()}" + } + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(ProvisioningInstallTask.TASK_NAME) + .withPluginClasspath(pluginClasspath) + .withGradleVersion(gradleVersion) + .build() + + then: + result.task(":" + ProvisioningInstallTask.TASK_NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The temporary provisioning provisioningFile1 should be deleted" + new File(testProjectDir.root, "build/provision") + .listFiles().size() == 0 + + where: + gradleVersion | _ + "4.4" | _ + "4.5" | _ + "4.6" | _ + "4.7" | _ + } + + 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/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy index 4facd4d9..2cec8717 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy @@ -25,8 +25,6 @@ class XcodeBuildCleanTask extends DefaultTask { super() dependsOn( - XcodePlugin.KEYCHAIN_CLEAN_TASK_NAME, - XcodePlugin.PROVISIONING_CLEAN_TASK_NAME, XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, XcodePlugin.DEPLOYGATE_CLEAN_TASK_NAME, diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index b97dae29..4c131270 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -101,8 +101,6 @@ class XcodePlugin implements Plugin { public static final String HOCKEYKIT_IMAGE_TASK_NAME = "hockeykitImage" public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" public static final String HOCKEYKIT_TASK_NAME = "hockeykit" - public static final String KEYCHAIN_CLEAN_TASK_NAME = "keychainClean" - public static final String KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME = "keychainRemove" public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' @@ -461,7 +459,6 @@ class XcodePlugin implements Plugin { for (XcodeTestRunTask xcodeTestRunTask : project.getTasks().withType(XcodeTestRunTask.class)) { if (xcodeTestRunTask.runOnDevice()) { xcodeTestRunTask.dependsOn(KeychainCreateTask.TASK_NAME, ProvisioningInstallTask.TASK_NAME) - xcodeTestRunTask.finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) } } } @@ -553,16 +550,6 @@ class XcodePlugin implements Plugin { it.keychainTimeout.set(xcodeBuildPluginExtension.signing.timeout) it.security.set(securityTool) } - - project.task(KEYCHAIN_CLEAN_TASK_NAME, type: KeychainCleanupTask, group: XCODE_GROUP_NAME) - - project.tasks.create(KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME, - KeychainRemoveFromSearchListTask.class) { - it.group = XCODE_GROUP_NAME - it.keyChainFile.set(xcodeBuildPluginExtension.signing.keyChainFile) - it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) - it.security.set(securityTool) - } } private void configureTest(Project project) { @@ -600,7 +587,6 @@ class XcodePlugin implements Plugin { .registeredProvisioning .set(it.registeredProvisioningFiles) } - project.task(PROVISIONING_CLEAN_TASK_NAME, type: ProvisioningCleanupTask, group: XCODE_GROUP_NAME) } private configurePackage(Project project) { @@ -615,16 +601,6 @@ class XcodePlugin implements Plugin { type: ReleaseNotesTask, group: XCODE_GROUP_NAME) - //ProvisioningCleanupTask provisioningCleanup = project.getTasks().getByName(PROVISIONING_CLEAN_TASK_NAME) - - //KeychainCleanupTask keychainCleanupTask = project.getTasks().getByName(KEYCHAIN_CLEAN_TASK_NAME) - -/* // disabled clean because of #115 - packageTask.doLast { - provisioningCleanup.clean() - keychainCleanupTask.clean() - } -*/ } private void configureModernPackager(Project project) { diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 5ad4410f..34e6aa4c 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -59,7 +59,8 @@ class Signing { * internal parameters */ private final Project project - private final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" + private + final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" CommandRunner commandRunner @Inject @@ -133,6 +134,17 @@ class Signing { entitlementsFile.set(new File(value)) } + @Deprecated + public void setMobileProvisionURI(String value) { + this.mobileProvisionList.add(value) + } + + @Deprecated + public void setMobileProvisionURI(String... values) { + println "setMobileProvisionURI : " + values + values.each { this.mobileProvisionList.add(it) } + } + @Override public String toString() { if (this.keychain != null) { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy index 4c2dbf83..2d78576c 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageLegacyTask.groovy @@ -12,12 +12,11 @@ import org.openbakery.CommandRunnerException import org.openbakery.bundle.ApplicationBundle import org.openbakery.codesign.Codesign import org.openbakery.codesign.CodesignParameters +import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask import org.openbakery.util.PathHelper import org.openbakery.xcode.Type -import org.openbakery.XcodePlugin -import org.openbakery.codesign.ProvisioningProfileReader class PackageLegacyTask extends AbstractDistributeTask { @@ -43,10 +42,6 @@ class PackageLegacyTask extends AbstractDistributeTask { ProvisioningInstallTask.TASK_NAME ) - finalizedBy( - XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME - ) - onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index c54ce4a5..b666e315 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -64,8 +64,6 @@ class PackageTaskIosAndTvOS extends DefaultTask { dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) - finalizedBy(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - onlyIf(new Spec() { @Override boolean isSatisfiedBy(Task task) { diff --git a/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy deleted file mode 100644 index 8119f081..00000000 --- a/plugin/src/main/groovy/org/openbakery/signing/AbstractKeychainTask.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package org.openbakery.signing - -import groovy.transform.CompileStatic -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.OutputFile -import org.openbakery.codesign.Security - -@CompileStatic -abstract class AbstractKeychainTask extends DefaultTask { - - @OutputFile - final RegularFileProperty keyChainFile = newOutputFile() - - final Property security = project.objects.property(Security) - final DirectoryProperty outputDirectory = newOutputDirectory() - - AbstractKeychainTask() { - setupGarbageCleaner() - } - - List getKeychainList() { - return security.get().getKeychainList() - } - - void setKeychainList(List keychainList) { - security.get().setKeychainList(keychainList) - } - - void removeGradleKeychainsFromSearchList() { - if (keyChainFile.present) { - logger.info("Remove the temporary keychain from search list") - List list = getKeychainList() - list.remove(keyChainFile.get()) - setKeychainList(list) - } - } - - void deleteTemporaryKeyChainFile() { - if (keyChainFile.present) { - logger.info("Delete the temporary keychain file") - keyChainFile.get().asFile.delete() - } - } - - private void setupGarbageCleaner() { - project.gradle.buildFinished { - removeGradleKeychainsFromSearchList() - deleteTemporaryKeyChainFile() - } - } -} diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy deleted file mode 100644 index da21f8ee..00000000 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCleanupTask.groovy +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openbakery.signing - -import org.gradle.api.tasks.TaskAction - -class KeychainCleanupTask extends AbstractKeychainTask { - - KeychainCleanupTask() { - super() - this.description = "Cleanup the keychain" - } - - - - @TaskAction - def clean() { -// if (project.xcodebuild.signing.keychain) { -// logger.debug("Nothing to cleanup") -// return -// } -// cleanupKeychain() - } - -} diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index fdde0029..7f4872c6 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -1,19 +1,23 @@ package org.openbakery.signing import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.codesign.Security import org.openbakery.extension.Signing import org.openbakery.util.FileUtil import org.openbakery.util.SystemUtil import org.openbakery.xcode.Version @CompileStatic -class KeychainCreateTask extends AbstractKeychainTask { +class KeychainCreateTask extends DefaultTask { @InputFile final RegularFileProperty certificateFile = newInputFile() @@ -24,6 +28,12 @@ class KeychainCreateTask extends AbstractKeychainTask { @Input final Property keychainTimeout = project.objects.property(Integer) + @OutputFile + final RegularFileProperty keyChainFile = newOutputFile() + + final Property security = project.objects.property(Security) + final DirectoryProperty outputDirectory = newOutputDirectory() + 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" @@ -60,6 +70,11 @@ class KeychainCreateTask extends AbstractKeychainTask { @TaskAction void create() { + project.gradle.buildFinished { + removeGradleKeychainsFromSearchList() + deleteTemporaryKeyChainFile() + } + createTemporaryCertificateFile() createKeyChainAndImportCertificate() addKeyChainToThePartitionList() @@ -88,13 +103,6 @@ class KeychainCreateTask extends AbstractKeychainTask { .importCertificate(temporaryCertificateFile, certificatePassword.get(), keyChainFile.asFile.get()) - - // Delete the temporary keychain on completion - project.gradle.buildFinished { - if (keyChainFile.asFile.get()) { - keyChainFile.asFile.get().delete() - } - } } private void addKeyChainToThePartitionList() { @@ -102,7 +110,7 @@ class KeychainCreateTask extends AbstractKeychainTask { if (systemVersion.minor >= 9) { List keychainList = getKeychainList() keychainList.add(keyChainFile.asFile.get()) - setKeychainList(keychainList) + populateKeyChain(keychainList) } if (systemVersion.minor >= 12) { @@ -118,4 +126,33 @@ class KeychainCreateTask extends AbstractKeychainTask { keyChainFile.asFile.get()) } } + + List getKeychainList() { + return security.get().getKeychainList() + } + + void populateKeyChain(List keychainList) { + security.get() + .setKeychainList(keychainList) + } + + private void deleteTemporaryKeyChainFile() { + if (keyChainFile.asFile.get()) { + keyChainFile.asFile.get().delete() + + logger.info("The temporary keychain file has been deleted") + } + } + + private void removeGradleKeychainsFromSearchList() { + if (keyChainFile.present) { + List list = getKeychainList() + list.removeIf { File file -> + return file.absolutePath == keyChainFile.get().asFile.absolutePath + } + populateKeyChain(list) + + logger.info("The temporary keychain has been removed from the search list") + } + } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTask.groovy deleted file mode 100644 index 02985e66..00000000 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTask.groovy +++ /dev/null @@ -1,20 +0,0 @@ -package org.openbakery.signing - -import org.gradle.api.tasks.TaskAction -import org.openbakery.XcodePlugin - -class KeychainRemoveFromSearchListTask extends AbstractKeychainTask { - - KeychainRemoveFromSearchListTask() { - super() - mustRunAfter(XcodePlugin.CRASHLYTICS_TASK_NAME) - this.description = "Removes the gradle keychain from the search list" - } - - - - @TaskAction - def remove() { - removeGradleKeychainsFromSearchList() - } -} diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy deleted file mode 100644 index 52829982..00000000 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningCleanupTask.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openbakery.signing - -import org.gradle.api.tasks.TaskAction -import org.openbakery.AbstractXcodeTask - - -class ProvisioningCleanupTask extends AbstractXcodeTask { - - ProvisioningCleanupTask() { - } - - @TaskAction - def clean() { -// if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { -// logger.debug("deleting {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) -// project.xcodebuild.signing.mobileProvisionDestinationRoot.deleteDir() -// -// if (project.xcodebuild.signing.mobileProvisionDestinationRoot.exists()) { -// logger.error("error deleting provisioning: {}", project.xcodebuild.signing.mobileProvisionDestinationRoot) -// } -// } else { -// logger.debug("Provisioning destination cleanup skipped because the destination directory does not exit") -// } -// -// File mobileprovisionPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/") -// -// if (mobileprovisionPath.exists()) { -// // find all the broken profile links that where created by this plugin -// String profileLinksToDelete = commandRunner.runWithResult(["find", "-L", mobileprovisionPath.absolutePath, "-name", ProvisioningInstallTask.PROVISIONING_NAME_BASE +"*", "-type", "l"]); -// String[] profiles = profileLinksToDelete.split("\n") -// for (String profile : profiles) { -// logger.debug("profile to delete {}", profile) -// new File(profile).delete(); -// } -// } else { -// logger.debug("nothing to cleanup") -// } - } -} diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy index 3eee6b1c..ee686b80 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningFile.groovy @@ -52,6 +52,10 @@ class ProvisioningFile implements Serializable { } String getFormattedName() { + return formattedName(uuid, file) + } + + public 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 7d2d65cb..34cc4566 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -9,6 +9,7 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputFiles import org.gradle.api.tasks.TaskAction import org.openbakery.CommandRunner @@ -24,13 +25,14 @@ class ProvisioningInstallTask extends Download { @OutputFiles final ListProperty registeredProvisioning = project.objects.listProperty(File) + @OutputDirectory + final Provider outputDirectory = project.layout.directoryProperty() + final ListProperty registeredProvisioningFiles = project.objects.listProperty(ProvisioningFile) final Property commandRunnerProperty = project.objects.property(CommandRunner) final Property plistHelperProperty = project.objects.property(PlistHelper) - final Provider outputDirectory = project.layout.directoryProperty() - public static final String PROVISIONING_NAME_BASE = "gradle-" public static final String TASK_NAME = "provisioningInstall" public static final String TASK_DESCRIPTION = "Installs the given provisioning profile" @@ -50,7 +52,6 @@ class ProvisioningInstallTask extends Download { outputDirectory.get().asFile.mkdirs() configureDownload() super.download() - deleteFilesOnExit(getOutputFiles()) postDownload() } @@ -76,6 +77,7 @@ class ProvisioningInstallTask extends Download { private void postDownload() { // For convenience we rename the mobile provisioning file in to a formatted name List files = rename() + deleteFilesOnExit(files.collect { it.file }) // Register it files.each(this.®isterProvisioning) @@ -94,7 +96,11 @@ class ProvisioningInstallTask extends Download { commandRunnerProperty.get(), plistHelperProperty.get()) - return new ProvisioningFile(file, + File renamedFile = new File(file.parentFile, + ProvisioningFile.formattedName(reader.getUUID(), file)) + file.renameTo(renamedFile) + + return new ProvisioningFile(renamedFile, reader.getApplicationIdentifier(), reader.getUUID(), reader.getTeamIdentifierPrefix(), diff --git a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy index e840ef6e..cf462311 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy @@ -247,20 +247,6 @@ class XcodeTestRunTaskSpecification extends Specification { !xcodeTestRunTestTask.getTaskDependencies().getDependencies().contains(project.getTasks().getByName(ProvisioningInstallTask.TASK_NAME)) } - def "when keychain dependency then also has finalized keychain remove"() { - when: - def bundleDirectory = createTestBundleForDeviceBuild() - xcodeTestRunTestTask = project.getTasks().getByPath(XcodePlugin.XCODE_TEST_RUN_TASK_NAME) - xcodeTestRunTestTask.setBundleDirectory(bundleDirectory) - project.evaluate() - - def finalized = xcodeTestRunTestTask.finalizedBy.getDependencies() - def keychainRemoveTask = project.getTasks().getByPath(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - then: - finalized.contains(keychainRemoveTask) - } - - def "has keychain dependency if device run"() { when: def bundleDirectory = createTestBundleForDeviceBuild() diff --git a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/packaging/PackageLegacyTaskSpecification.groovy similarity index 97% rename from plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy rename to plugin/src/test/groovy/org/openbakery/packaging/PackageLegacyTaskSpecification.groovy index bdc7e919..423a0955 100644 --- a/plugin/src/test/groovy/org/openbakery/packaging/PackageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/packaging/PackageLegacyTaskSpecification.groovy @@ -6,7 +6,6 @@ import org.apache.commons.lang.RandomStringUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin import org.openbakery.output.StyledTextOutputStub import org.openbakery.signing.KeychainCreateTask import org.openbakery.signing.ProvisioningInstallTask @@ -21,7 +20,7 @@ import spock.lang.Specification import java.util.zip.ZipEntry import java.util.zip.ZipFile -class PackageTaskSpecification extends Specification { +class PackageLegacyTaskSpecification extends Specification { Project project @@ -447,15 +446,6 @@ class PackageTaskSpecification extends Specification { } - def "finalized"() { - when: - def finalized = packageTask.finalizedBy.getDependencies() - def keychainRemoveTask = project.getTasks().getByPath(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME) - then: - finalized.contains(keychainRemoveTask) - } - - def "delete CFBundleResourceSpecification"() { given: mockExampleApp(false, true) diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCleanupTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCleanupTaskSpecification.groovy deleted file mode 100644 index c649a011..00000000 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCleanupTaskSpecification.groovy +++ /dev/null @@ -1,151 +0,0 @@ -package org.openbakery.signing - -import org.apache.commons.io.FileUtils -import org.gradle.api.Project -import org.gradle.testfixtures.ProjectBuilder -import org.openbakery.CommandRunner -import org.openbakery.XcodeBuildPluginExtension -import org.openbakery.XcodePlugin -import spock.lang.Specification - - -class KeychainCleanupTaskSpecification extends Specification { - - Project project - - KeychainCleanupTask keychainCleanupTask - - CommandRunner commandRunner = Mock(CommandRunner) - File keychainDestinationFile - File certificateFile - - File tmpDirectory - File loginKeychain - - def setup() { - File projectDir = new File("../example/iOS/ExampleWatchkit") - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - tmpDirectory = new File(System.getProperty("java.io.tmpdir"), 'gradle-xcodebuild') - project.buildDir = new File(tmpDirectory, 'build').absoluteFile - - loginKeychain = new File(tmpDirectory, "login.keychain") - FileUtils.writeStringToFile(loginKeychain, "dummy") - - - project.apply plugin: org.openbakery.XcodePlugin - - keychainCleanupTask = project.tasks.findByName(XcodePlugin.KEYCHAIN_CLEAN_TASK_NAME); - keychainCleanupTask.commandRunner = commandRunner - keychainCleanupTask.security.commandRunner = commandRunner - - - certificateFile = File.createTempFile("test", ".cert") - certificateFile.deleteOnExit() - keychainDestinationFile = new File(project.xcodebuild.signing.signingDestinationRoot, certificateFile.getName()) - - } - - def cleanup() { - FileUtils.deleteDirectory(project.buildDir) - FileUtils.deleteDirectory(tmpDirectory) - } - - def "delete keychain OS X 10.8"() { - given: - System.setProperty("os.version", "10.8.0"); - - String result = " \""+ loginKeychain.absolutePath + "\"\n" + - " \"/Library/Keychains/" + XcodeBuildPluginExtension.KEYCHAIN_NAME_BASE + "delete-me.keychain\"\n" + - " \"/Library/Keychains/System.keychain\""; - commandRunner.runWithResult(["security", "list-keychains"]) >> result - - when: - keychainCleanupTask.clean() - - then: - 1 * commandRunner.run(["security", "list-keychains", "-s", loginKeychain.absolutePath]) - - } - - def "delete keychain OS X 10.9"() { - given: - System.setProperty("os.version", "10.9.0"); - - String result = " \""+ loginKeychain.absolutePath + "\"\n" + - " \"/Library/Keychains/" + XcodeBuildPluginExtension.KEYCHAIN_NAME_BASE + "delete-me.keychain\"\n" + - " \"/Library/Keychains/System.keychain\""; - - commandRunner.runWithResult(["security", "list-keychains"]) >> result - - when: - keychainCleanupTask.clean() - - then: - 1 * commandRunner.run(["security", "list-keychains", "-s", loginKeychain.absolutePath]) - - } - - String getSecurityList() { - return " \""+ loginKeychain.absolutePath + "\n" + - " \"/Users/me/Go/pipelines/Build-Appstore/build/codesign/gradle-1431356246879.keychain\"\n" + - " \"/Users/me/Go/pipelines/Build-Test/build/codesign/gradle-1431356877451.keychain\"\n" + - " \"/Users/me/Go/pipelines/Build-Continuous/build/codesign/gradle-1431419900260.keychain\"\n" + - " \"/Library/Keychains/System.keychain\"" - - } - - - def "keychain list update"() { - given: - commandRunner.runWithResult(["security", "list-keychains"]) >> getSecurityList() - - when: - keychainCleanupTask.removeGradleKeychainsFromSearchList() - - then: - 1 * commandRunner.run(["security", "list-keychains", "-s", loginKeychain.absolutePath]) - - } - - - def "get keychain list"() { - given: - commandRunner.runWithResult(["security", "list-keychains"]) >> getSecurityList() - - when: - List keychainList = keychainCleanupTask.getKeychainList() - - then: - keychainList.size == 1 - } - - - def "remove only missing keychain in list"() { - given: - System.setProperty("os.version", "10.9.0"); - - File keychainFile = new File(project.buildDir, "gradle.keychain"); - FileUtils.writeStringToFile(keychainFile, "dummy"); - - String keychainFileName = keychainFile.absolutePath - - String result = " \"" + loginKeychain.absolutePath + "\n" + - " \"" + keychainFileName + "\n" + - " \"/Library/Keychains/System.keychain\""; - - commandRunner.runWithResult(["security", "list-keychains"]) >> result - - - def commandList - - when: - keychainCleanupTask.removeGradleKeychainsFromSearchList() - - then: - 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security", "list-keychains", "-s", loginKeychain.absolutePath, keychainFileName] - //1 * commandRunner.run(["security", "list-keychains", "-s", "/Users/me/Library/Keychains/login.keychain", keychainFileName]) - - } - -} diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTaskSpecification.groovy deleted file mode 100644 index f72ef2b1..00000000 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainRemoveFromSearchListTaskSpecification.groovy +++ /dev/null @@ -1,156 +0,0 @@ -package org.openbakery.signing - -import groovy.mock.interceptor.MockFor -import org.apache.commons.io.FileUtils -import org.gradle.api.Project -import org.gradle.testfixtures.ProjectBuilder -import org.junit.Test -import org.openbakery.CommandRunner -import org.openbakery.XcodePlugin -import spock.lang.Specification - -/** - * User: rene - * Date: 14/10/15 - */ -class KeychainRemoveFromSearchListTaskSpecification extends Specification { - - Project project - - KeychainRemoveFromSearchListTask task - File tmpDirectory - File loginKeychain - CommandRunner commandRunner = Mock(CommandRunner) - - def setup() { - File projectDir = new File("../example/iOS/ExampleWatchkit") - - tmpDirectory = new File(System.getProperty("java.io.tmpdir"), 'gradle-xcodebuild') - - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.buildDir = new File(tmpDirectory, 'build').absoluteFile - - project.apply plugin: org.openbakery.XcodePlugin - - task = project.tasks.findByName(XcodePlugin.KEYCHAIN_REMOVE_SEARCH_LIST_TASK_NAME); - task.commandRunner = commandRunner - task.security.commandRunner = commandRunner - - loginKeychain = new File(tmpDirectory, "login.keychain") - FileUtils.writeStringToFile(loginKeychain, "dummy") - - - } - - def cleanup() { - FileUtils.deleteDirectory(project.buildDir) - FileUtils.deleteDirectory(tmpDirectory) - } - - def "check group"() { - when: - true - - then: - task.group == XcodePlugin.XCODE_GROUP_NAME - } - - - String createSecurityListResult(String... keychainFiles) { - - StringBuilder builder = new StringBuilder(); - builder.append(" \"") - builder.append(loginKeychain.absolutePath) - builder.append("\"\n") - - - for (String keychainFile in keychainFiles) { - builder.append(" \"") - builder.append(keychainFile) - builder.append("\"\n") - } - - builder.append(" \"/Library/Keychains/System.keychain\"") - return builder.toString() - } - - def "remove"() { - def commandList; - - given: - def securityList = createSecurityListResult( - "/Users/me/Go/pipelines/Build-Appstore/build/codesign/gradle-1431356246879.keychain", - "/Users/me/Go/pipelines/Build-Test/build/codesign/gradle-1431356877451.keychain", - "/Users/me/Go/pipelines/Build-Continuous/build/codesign/gradle-1431419900260.keychain" - ) - - commandRunner.runWithResult(["security", "list-keychains"]) >> securityList - - when: - task.remove() - - then: - 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security", "list-keychains", "-s", loginKeychain.absolutePath] - - } - - def "remove with existing files"() { - def commandList; - - given: - File dummyKeychain = new File(project.buildDir, "gradle-1234.keychain") - FileUtils.writeStringToFile(dummyKeychain, "dummy"); - def securityList = createSecurityListResult(dummyKeychain.getAbsolutePath()) - commandRunner.runWithResult(["security", "list-keychains"]) >> securityList - - when: - task.remove() - - then: - 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security", "list-keychains", "-s", loginKeychain.absolutePath, dummyKeychain.getAbsolutePath()] - } - - - def "remove current used keychain"() { - def commandList; - - given: - File dummyKeychain = new File(project.buildDir, "gradle-1234.keychain") - FileUtils.writeStringToFile(dummyKeychain, "dummy"); - def securityList = createSecurityListResult(dummyKeychain.getAbsolutePath()) - commandRunner.runWithResult(["security", "list-keychains"]) >> securityList - - project.xcodebuild.signing.keychain = dummyKeychain - - when: - task.remove() - - then: - 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security", "list-keychains", "-s", loginKeychain.absolutePath] - } - - - def "remove current used internal keychain"() { - def commandList; - - given: - project.xcodebuild.signing.signingDestinationRoot = project.buildDir - - FileUtils.writeStringToFile(project.xcodebuild.signing.keychainPathInternal, "dummy"); - def securityList = createSecurityListResult(project.xcodebuild.signing.keychainPathInternal.getAbsolutePath()) - commandRunner.runWithResult(["security", "list-keychains"]) >> securityList - - when: - task.remove() - - then: - 1 * commandRunner.run(_) >> { arguments -> commandList = arguments[0] } - commandList == ["security", "list-keychains", "-s", loginKeychain.absolutePath] - } - - - -} diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy index 946c0497..43516ea3 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskSpecification.groovy @@ -49,10 +49,6 @@ class ProvisioningInstallTaskSpecification extends Specification { setup: project.xcodebuild.signing.mobileProvisionURI = testMobileProvision2.toURI().toString() - project.extensions.getByType(XcodeBuildPluginExtension) - .signing - .mobileProvisionList - String name2 = formatProvisionFileName(testMobileProvision2) File downloadedFile2 = new File(tmpDirectory.root, "build/provision/" + name2) @@ -78,13 +74,41 @@ class ProvisioningInstallTaskSpecification extends Specification { project.buildDir = tmpDirectory.newFolder(alternateBuildFolderName) project.xcodebuild.signing.mobileProvisionURI = testMobileProvision2.toURI().toString() - project.extensions.getByType(XcodeBuildPluginExtension) + String name2 = formatProvisionFileName(testMobileProvision2) + + File downloadedFile2 = new File(tmpDirectory.root, "${alternateBuildFolderName}/provision/" + name2) + File libraryFile2 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name2) + + when: + subject.download() + + then: + noExceptionThrown() + + and: + downloadedFile2.text == testMobileProvision2.text + downloadedFile2.exists() + + libraryFile2.text == testMobileProvision2.text + libraryFile2.exists() + } + + def "Should process without error multiple provisioning files by using the deprecated `setMobileProvisionURI` property"() { + + setup: + project.extensions + .findByType(XcodeBuildPluginExtension) .signing - .mobileProvisionList + .setMobileProvisionURI(testMobileProvision1.toURI().toString(), + testMobileProvision2.toURI().toString()) + String name1 = formatProvisionFileName(testMobileProvision1) String name2 = formatProvisionFileName(testMobileProvision2) - File downloadedFile2 = new File(tmpDirectory.root, "${alternateBuildFolderName}/provision/" + name2) + File downloadedFile1 = new File(tmpDirectory.root, "build/provision/" + name1) + File libraryFile1 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name1) + + File downloadedFile2 = new File(tmpDirectory.root, "build/provision/" + name2) File libraryFile2 = new File(ProvisioningInstallTask.PROVISIONING_DIR, name2) when: @@ -93,6 +117,13 @@ class ProvisioningInstallTaskSpecification extends Specification { then: noExceptionThrown() + and: + downloadedFile1.text == testMobileProvision1.text + downloadedFile1.exists() + + libraryFile1.text == testMobileProvision1.text + libraryFile1.exists() + and: downloadedFile2.text == testMobileProvision2.text downloadedFile2.exists() @@ -101,12 +132,14 @@ class ProvisioningInstallTaskSpecification extends Specification { libraryFile2.exists() } - def "Should process without error multiple provisioning files"() { + def "Should process without error multiple provisioning files by using directly the `mobileProvisionList` property"() { setup: - project.xcodebuild.signing.mobileProvisionURI = [testMobileProvision1, - testMobileProvision2] - .collect { it.toURI().toString() } + project.extensions + .findByType(XcodeBuildPluginExtension) + .signing + .mobileProvisionList.set([testMobileProvision1.toURI().toString(), + testMobileProvision2.toURI().toString()]) String name1 = formatProvisionFileName(testMobileProvision1) String name2 = formatProvisionFileName(testMobileProvision2) From aa159eaffe4748f8a6c0e407d17dba36d1ccdb19 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 11:19:50 +0100 Subject: [PATCH 102/121] Cleaning up --- .../XcodeBuildPluginExtension.groovy | 2 +- .../org/openbakery/extension/Signing.groovy | 62 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 5b29a708..1409177c 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -109,7 +109,7 @@ class XcodeBuildPluginExtension { configureServices() configurePaths() - this.signing = project.objects.newInstance(Signing, project) + this.signing = project.objects.newInstance(Signing, project, commandRunner) this.variableResolver = new VariableResolver(project) this.dstRoot = { diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 34e6aa4c..6d25bf45 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -59,14 +59,15 @@ class Signing { * internal parameters */ private final Project project - private - final String keychainName = KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain" - CommandRunner commandRunner + private final CommandRunner commandRunner @Inject - Signing(Project project) { + Signing(Project project, + CommandRunner commandRunner) { + this.commandRunner = commandRunner this.project = project + this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) @@ -80,19 +81,19 @@ class Signing { } })) - this.commandRunner = new CommandRunner() - // Entitlements support this.entitlementsMap = project.objects.property(Map) this.entitlementsFile = project.layout.fileProperty() - this.keyChainFile.set(signingDestinationRoot.file(keychainName)) + this.keyChainFile.set(signingDestinationRoot.file(KEYCHAIN_NAME_BASE + + System.currentTimeMillis() + + ".keychain")) this.timeout.set(3600) this.xcConfigFile = project.layout.fileProperty() - this.xcConfigFile.set(project.layout.buildDirectory.file(PathHelper.FOLDER_ARCHIVE - + "/" - + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) + this.xcConfigFile.set(project.layout + .buildDirectory + .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) } void setKeychain(Object keychain) { @@ -113,7 +114,7 @@ class Signing { return project.file(keychainPathInternal) } - public void entitlements(Map entitlements) { + void entitlements(Map entitlements) { if (!this.entitlementsMap.present) { this.entitlementsMap.set(entitlements) } else { @@ -135,33 +136,15 @@ class Signing { } @Deprecated - public void setMobileProvisionURI(String value) { + void setMobileProvisionURI(String value) { this.mobileProvisionList.add(value) } @Deprecated - public void setMobileProvisionURI(String... values) { - println "setMobileProvisionURI : " + values + void setMobileProvisionURI(String... values) { values.each { this.mobileProvisionList.add(it) } } - @Override - public String toString() { - if (this.keychain != null) { - return "Signing{" + - " identity='" + identity + '\'' + - ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + - ", keychain='" + keychain + '\'' + - '}'; - } - return "Signing{" + - " identity='" + identity + '\'' + - ", certificateURI='" + certificate.getOrNull() + '\'' + - ", certificatePassword='" + certificatePassword.getOrNull() + '\'' + - ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + - '}'; - } - CodesignParameters getCodesignParameters() { CodesignParameters result = new CodesignParameters() result.signingIdentity = getIdentity() @@ -201,4 +184,21 @@ class Signing { "-passin", "pass:" + certificatePassword.get()]) } + + @Override + public String toString() { + if (this.keychain != null) { + return "Signing{" + + " identity='" + identity + '\'' + + ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + + ", keychain='" + keychain + '\'' + + '}'; + } + return "Signing{" + + " identity='" + identity + '\'' + + ", certificateURI='" + certificate.getOrNull() + '\'' + + ", certificatePassword='" + certificatePassword.getOrNull() + '\'' + + ", mobileProvisionURI='" + mobileProvisionList.get() + '\'' + + '}'; + } } From f1eaac9dfad09d6bb482e29b9a09d3014f32ccc6 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 11:30:12 +0100 Subject: [PATCH 103/121] Simplify declaration --- .../XcodeBuildPluginExtension.groovy | 1 - .../groovy/org/openbakery/XcodePlugin.groovy | 44 ++++++++++--------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 1409177c..a6e1f315 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -43,7 +43,6 @@ class XcodeBuildPluginExtension { final Signing signing - private static Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 4c131270..e8d534e8 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -47,6 +47,7 @@ import org.openbakery.crashlytics.CrashlyticsUploadTask import org.openbakery.deploygate.DeployGateCleanTask import org.openbakery.deploygate.DeployGatePluginExtension import org.openbakery.deploygate.DeployGateUploadTask +import org.openbakery.extension.Signing import org.openbakery.hockeyapp.HockeyAppCleanTask import org.openbakery.hockeyapp.HockeyAppPluginExtension import org.openbakery.hockeyapp.HockeyAppUploadTask @@ -102,7 +103,6 @@ class XcodePlugin implements Plugin { public static final String HOCKEYKIT_CLEAN_TASK_NAME = "hockeykitClean" public static final String HOCKEYKIT_TASK_NAME = "hockeykit" public static final String INFOPLIST_MODIFY_TASK_NAME = 'infoplistModify' - public static final String PROVISIONING_CLEAN_TASK_NAME = 'provisioningClean' public static final String PACKAGE_RELEASE_NOTES_TASK_NAME = 'packageReleaseNotes' public static final String APPSTORE_UPLOAD_TASK_NAME = 'appstoreUpload' public static final String APPSTORE_VALIDATE_TASK_NAME = 'appstoreValidate' @@ -132,6 +132,7 @@ class XcodePlugin implements Plugin { public static final String SDK_IPHONESIMULATOR = "iphonesimulator" + private Signing signingExtension private XcodeBuildPluginExtension xcodeBuildPluginExtension private InfoPlistExtension infoPlistExtension @@ -435,13 +436,14 @@ class XcodePlugin implements Plugin { } - void configureExtensions(Project project) { - xcodeBuildPluginExtension = project.extensions.create("xcodebuild", + this.xcodeBuildPluginExtension = project.extensions.create("xcodebuild", XcodeBuildPluginExtension, project) - infoPlistExtension = project.extensions.create("infoplist", + this.signingExtension = xcodeBuildPluginExtension.signing + + this.infoPlistExtension = project.extensions.create("infoplist", InfoPlistExtension, project) @@ -488,13 +490,13 @@ class XcodePlugin implements Plugin { PrepareXcodeArchivingTask.class) { it.group = XCODE_GROUP_NAME - it.certificateFriendlyName.set(xcodeBuildPluginExtension.signing.certificateFriendlyName) + it.certificateFriendlyName.set(signingExtension.certificateFriendlyName) it.commandRunnerProperty.set(commandRunner) it.configurationBundleIdentifier.set(infoPlistExtension.configurationBundleIdentifier) - it.entitlementsFile.set(xcodeBuildPluginExtension.signing.entitlementsFile) - it.outputFile.set(xcodeBuildPluginExtension.signing.xcConfigFile) + it.entitlementsFile.set(signingExtension.entitlementsFile) + it.outputFile.set(signingExtension.xcConfigFile) it.plistHelperProperty.set(plistHelper) - it.registeredProvisioningFiles.set(xcodeBuildPluginExtension.signing.registeredProvisioningFiles) + it.registeredProvisioningFiles.set(signingExtension.registeredProvisioningFiles) } project.getTasks().create(XcodeBuildArchiveTaskIosAndTvOS.NAME, @@ -506,7 +508,7 @@ class XcodePlugin implements Plugin { it.scheme.set(xcodeBuildPluginExtension.scheme) it.xcode.set(xcode) it.xcodeVersion.set(xcodeBuildPluginExtension.version) - it.xcConfigFile.set(xcodeBuildPluginExtension.signing.xcConfigFile) + it.xcConfigFile.set(signingExtension.xcConfigFile) it.xcodeServiceProperty.set(xcodeBuildPluginExtension.xcodeServiceProperty) } @@ -543,11 +545,11 @@ class XcodePlugin implements Plugin { private void configureKeychain(Project project) { project.tasks.create(KeychainCreateTask.TASK_NAME, KeychainCreateTask.class) { it.group = XCODE_GROUP_NAME - it.certificateFile.set(xcodeBuildPluginExtension.signing.certificate) - it.certificatePassword.set(xcodeBuildPluginExtension.signing.certificatePassword) - it.outputDirectory.set(xcodeBuildPluginExtension.signing.signingDestinationRoot) - it.keyChainFile.set(xcodeBuildPluginExtension.signing.keyChainFile) - it.keychainTimeout.set(xcodeBuildPluginExtension.signing.timeout) + it.certificateFile.set(signingExtension.certificate) + it.certificatePassword.set(signingExtension.certificatePassword) + it.outputDirectory.set(signingExtension.signingDestinationRoot) + it.keyChainFile.set(signingExtension.keyChainFile) + it.keychainTimeout.set(signingExtension.timeout) it.security.set(securityTool) } } @@ -573,17 +575,17 @@ class XcodePlugin implements Plugin { it.group = XCODE_GROUP_NAME it.commandRunnerProperty.set(commandRunner) - it.mobileProvisioningList.set(xcodeBuildPluginExtension.signing.mobileProvisionList) - it.outputDirectory.set(xcodeBuildPluginExtension.signing.provisioningDestinationRoot) + it.mobileProvisioningList.set(signingExtension.mobileProvisionList) + it.outputDirectory.set(signingExtension.provisioningDestinationRoot) it.plistHelperProperty.set(plistHelper) it.plistHelperProperty.set(plistHelper) // We use the result of the task to populate the read only values - xcodeBuildPluginExtension.signing + signingExtension .registeredProvisioningFiles .set(it.registeredProvisioning) - xcodeBuildPluginExtension.signing + signingExtension .registeredProvisioning .set(it.registeredProvisioningFiles) } @@ -610,12 +612,12 @@ class XcodePlugin implements Plugin { it.bitCode.set(xcodeBuildPluginExtension.bitcode) it.buildType.set(xcodeBuildPluginExtension.type) - it.certificateFriendlyName.set(xcodeBuildPluginExtension.signing.certificateFriendlyName) + it.certificateFriendlyName.set(signingExtension.certificateFriendlyName) it.commandRunner.set(xcodeBuildPluginExtension.commandRunner) it.plistHelper.set(xcodeBuildPluginExtension.plistHelper) - it.registeredProvisioningFiles.set(xcodeBuildPluginExtension.signing.registeredProvisioning) + it.registeredProvisioningFiles.set(signingExtension.registeredProvisioning) it.scheme.set(xcodeBuildPluginExtension.scheme) - it.signingMethod.set(xcodeBuildPluginExtension.signing.signingMethod) + it.signingMethod.set(signingExtension.signingMethod) } } From 1a1cffc6879280c95bb511b34113c141aa71323b Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 11:34:36 +0100 Subject: [PATCH 104/121] Simplify declaration --- .../groovy/org/openbakery/XcodePlugin.groovy | 1 - .../org/openbakery/extension/Signing.groovy | 32 +++++++------------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index e8d534e8..c643975d 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -85,7 +85,6 @@ class XcodePlugin implements Plugin { public static final String XCODE_TEST_TASK_NAME = "xcodetest" public static final String XCODE_BUILD_FOR_TEST_TASK_NAME = "xcodebuildForTest" public static final String XCODE_TEST_RUN_TASK_NAME = "xcodetestrun" - public static final String ARCHIVE_TASK_NAME = "archive" public static final String SIMULATORS_LIST_TASK_NAME = "simulatorsList" public static final String SIMULATORS_CREATE_TASK_NAME = "simulatorsCreate" public static final String SIMULATORS_CLEAN_TASK_NAME = "simulatorsClean" diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 6d25bf45..fe9dee14 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -26,10 +26,10 @@ class Signing { final ListProperty mobileProvisionList = project.objects.listProperty(String) final Property timeout = project.objects.property(Integer) final Property signingMethod = project.objects.property(SigningMethod) - final Property certificateFriendlyName - final Property certificatePassword - final RegularFileProperty certificate - final RegularFileProperty entitlementsFile + final Property certificateFriendlyName = project.objects.property(String) + final Property certificatePassword = project.objects.property(String) + final RegularFileProperty certificate = project.layout.fileProperty() + final RegularFileProperty entitlementsFile = project.layout.fileProperty() final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() @@ -40,21 +40,20 @@ class Signing { final Provider> registeredProvisioning = project.objects.listProperty(ProvisioningFile) @Internal - Object keychainPathInternal - - @Internal - final RegularFileProperty xcConfigFile + final RegularFileProperty xcConfigFile = project.layout.fileProperty() @Deprecated - final Property> entitlementsMap + final Property> entitlementsMap = project.objects.property(Map) - public static final String KEYCHAIN_NAME_BASE = "gradle-" - private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ + @Internal + Object keychainPathInternal String identity - String plugin + public static final String KEYCHAIN_NAME_BASE = "gradle-" + private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ + /** * internal parameters */ @@ -70,10 +69,6 @@ class Signing { this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) - - this.certificate = project.layout.fileProperty() - this.certificatePassword = project.objects.property(String) - this.certificateFriendlyName = project.objects.property(String) this.certificateFriendlyName.set(certificate.map(new Transformer() { @Override String transform(RegularFile regularFile) { @@ -81,16 +76,11 @@ class Signing { } })) - // Entitlements support - this.entitlementsMap = project.objects.property(Map) - this.entitlementsFile = project.layout.fileProperty() - this.keyChainFile.set(signingDestinationRoot.file(KEYCHAIN_NAME_BASE + System.currentTimeMillis() + ".keychain")) this.timeout.set(3600) - this.xcConfigFile = project.layout.fileProperty() this.xcConfigFile.set(project.layout .buildDirectory .file(PathHelper.FOLDER_ARCHIVE + "/" + PathHelper.GENERATED_XCARCHIVE_FILE_NAME)) From 0b3c0abee7803b7272de517e23009ade9b5485ef Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 12:02:25 +0100 Subject: [PATCH 105/121] More adjustements --- .../XcodeBuildPluginExtension.groovy | 29 +++++++------------ .../groovy/org/openbakery/XcodePlugin.groovy | 5 ++-- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index a6e1f315..e5d3b3e5 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -32,14 +32,13 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory class XcodeBuildPluginExtension { - public final static KEYCHAIN_NAME_BASE = "gradle-" - final Property bitcode - final Property version - final Property scheme - final DirectoryProperty archiveDirectory - final DirectoryProperty schemeArchiveFile - final Property xcodeServiceProperty + final Property bitcode = project.objects.property(Boolean) + final Property version = project.objects.property(String) + final Property scheme = project.objects.property(String) + final DirectoryProperty archiveDirectory = project.layout.directoryProperty() + final DirectoryProperty schemeArchiveFile = project.layout.directoryProperty() + final Property xcodeServiceProperty = project.objects.property(XcodeService) final Signing signing @@ -78,7 +77,6 @@ class XcodeBuildPluginExtension { Devices devices = Devices.UNIVERSAL - CommandRunner commandRunner VariableResolver variableResolver PlistHelper plistHelper @@ -91,19 +89,14 @@ class XcodeBuildPluginExtension { * internal parameters */ private final Project project + private final CommandRunner commandRunner - public XcodeBuildPluginExtension(Project project) { - commandRunner = new CommandRunner() - plistHelper = new PlistHelper(commandRunner) - + XcodeBuildPluginExtension(Project project, + CommandRunner commandRunner) { this.project = project - this.bitcode = project.objects.property(Boolean) - this.version = project.objects.property(String) - this.scheme = project.objects.property(String) + this.commandRunner = commandRunner - this.xcodeServiceProperty = project.objects.property(XcodeService) - this.archiveDirectory = project.layout.directoryProperty() - this.schemeArchiveFile = project.layout.directoryProperty() + plistHelper = new PlistHelper(commandRunner) configureServices() configurePaths() diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index c643975d..82a0106c 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -438,7 +438,8 @@ class XcodePlugin implements Plugin { void configureExtensions(Project project) { this.xcodeBuildPluginExtension = project.extensions.create("xcodebuild", XcodeBuildPluginExtension, - project) + project, + commandRunner) this.signingExtension = xcodeBuildPluginExtension.signing @@ -612,7 +613,7 @@ class XcodePlugin implements Plugin { it.bitCode.set(xcodeBuildPluginExtension.bitcode) it.buildType.set(xcodeBuildPluginExtension.type) it.certificateFriendlyName.set(signingExtension.certificateFriendlyName) - it.commandRunner.set(xcodeBuildPluginExtension.commandRunner) + it.commandRunner.set(this.commandRunner) it.plistHelper.set(xcodeBuildPluginExtension.plistHelper) it.registeredProvisioningFiles.set(signingExtension.registeredProvisioning) it.scheme.set(xcodeBuildPluginExtension.scheme) From 89141a20204ca8aa5dfd077f94407566614be407 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 12:31:58 +0100 Subject: [PATCH 106/121] Adjust paths --- .../org/openbakery/XcodeBuildCleanTask.groovy | 17 ++- .../XcodeBuildPluginExtension.groovy | 106 +++--------------- .../openbakery/coverage/CoverageTask.groovy | 21 ++-- ...deBuildPluginExtensionSpecification.groovy | 10 +- .../XcodeTestRunTaskSpecification.groovy | 2 +- .../XcodeTestTaskSpecification.groovy | 2 +- .../coverage/CoverageTaskSpecification.groovy | 10 +- .../signing/SigningSpecification.groovy | 6 +- .../DestinationResolverSpecification.groovy | 24 +--- 9 files changed, 58 insertions(+), 140 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy index 2cec8717..d3c88ecf 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildCleanTask.groovy @@ -24,20 +24,19 @@ class XcodeBuildCleanTask extends DefaultTask { XcodeBuildCleanTask() { super() - dependsOn( - XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, - XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, - XcodePlugin.DEPLOYGATE_CLEAN_TASK_NAME, - ) + dependsOn(XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, + XcodePlugin.HOCKEYAPP_CLEAN_TASK_NAME, + XcodePlugin.DEPLOYGATE_CLEAN_TASK_NAME) + this.description = "Cleans up the generated files from the previous build" } @TaskAction def clean() { - project.xcodebuild.dstRoot.deleteDir() - project.xcodebuild.objRoot.deleteDir() - project.xcodebuild.symRoot.deleteDir() - project.xcodebuild.sharedPrecompsDir.deleteDir() + project.xcodebuild.dstRoot.get().deleteDir() + project.xcodebuild.objRoot.get().deleteDir() + project.xcodebuild.symRoot.get().deleteDir() + project.xcodebuild.sharedPrecompsDir.get().deleteDir() } } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index e5d3b3e5..2f48c798 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -38,13 +38,15 @@ class XcodeBuildPluginExtension { final Property scheme = project.objects.property(String) final DirectoryProperty archiveDirectory = project.layout.directoryProperty() final DirectoryProperty schemeArchiveFile = project.layout.directoryProperty() + final DirectoryProperty dstRoot = project.layout.directoryProperty() + final DirectoryProperty objRoot = project.layout.directoryProperty() + final DirectoryProperty symRoot = project.layout.directoryProperty() + final DirectoryProperty sharedPrecompsDir = project.layout.directoryProperty() + final DirectoryProperty derivedDataPath = project.layout.directoryProperty() final Property xcodeServiceProperty = project.objects.property(XcodeService) final Signing signing - private static Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) - - XcodebuildParameters _parameters = new XcodebuildParameters() String infoPlist = null @@ -54,11 +56,6 @@ class XcodeBuildPluginExtension { Type type = Type.iOS String target - Object dstRoot - Object objRoot - Object symRoot - Object sharedPrecompsDir - Object derivedDataPath def additionalParameters = null String bundleNameSuffix = null @@ -91,6 +88,8 @@ class XcodeBuildPluginExtension { private final Project project private final CommandRunner commandRunner + private static final Logger logger = LoggerFactory.getLogger(XcodeBuildPluginExtension.class) + XcodeBuildPluginExtension(Project project, CommandRunner commandRunner) { this.project = project @@ -104,25 +103,11 @@ class XcodeBuildPluginExtension { this.signing = project.objects.newInstance(Signing, project, commandRunner) this.variableResolver = new VariableResolver(project) - this.dstRoot = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("dst") - } - - this.objRoot = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("obj") - } - - this.symRoot = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("sym") - } - - this.sharedPrecompsDir = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("shared") - } - - this.derivedDataPath = { - return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve("derivedData") - } + this.dstRoot.set(project.layout.buildDirectory.dir("dst")) + this.objRoot.set(project.layout.buildDirectory.dir("obj")) + this.symRoot.set(project.layout.buildDirectory.dir("sym")) + this.sharedPrecompsDir.set(project.layout.buildDirectory.dir("shared")) + this.derivedDataPath.set(project.layout.buildDirectory.dir("derivedData")) } private void configureServices() { @@ -164,61 +149,6 @@ class XcodeBuildPluginExtension { return null } - void setDerivedDataPath(File derivedDataPath) { - this.derivedDataPath = derivedDataPath - } - - void setDstRoot(File dstRoot) { - this.dstRoot = dstRoot - } - - void setObjRoot(File objRoot) { - this.objRoot = objRoot - } - - void setSymRoot(File symRoot) { - this.symRoot = symRoot - } - - void setSharedPrecompsDir(File sharedPrecompsDir) { - this.sharedPrecompsDir = sharedPrecompsDir - } - - File getDstRoot() { - if (dstRoot instanceof File) { - return dstRoot - } - return project.file(dstRoot) - } - - File getObjRoot() { - if (objRoot instanceof File) { - return objRoot - } - return project.file(objRoot) - } - - File getSymRoot() { - if (symRoot instanceof File) { - return symRoot - } - return project.file(symRoot) - } - - File getSharedPrecompsDir() { - if (sharedPrecompsDir instanceof File) { - return sharedPrecompsDir - } - return project.file(sharedPrecompsDir) - } - - File getDerivedDataPath() { - if (derivedDataPath instanceof File) { - return derivedDataPath - } - return project.file(derivedDataPath) - } - void signing(Closure closure) { ConfigureUtil.configure(closure, this.signing) } @@ -344,7 +274,7 @@ class XcodeBuildPluginExtension { } } } - return new File(getSymRoot(), path) + return new File(getSymRoot().asFile.get(), path) } @@ -487,11 +417,11 @@ class XcodeBuildPluginExtension { result.type = this.type result.workspace = getWorkspace() result.configuration = this.configuration - result.dstRoot = this.getDstRoot() - result.objRoot = this.getObjRoot() - result.symRoot = this.getSymRoot() - result.sharedPrecompsDir = this.getSharedPrecompsDir() - result.derivedDataPath = this.getDerivedDataPath() + result.dstRoot = this.getDstRoot().asFile.getOrNull() + result.objRoot = this.getObjRoot().asFile.getOrNull() + result.symRoot = this.getSymRoot().asFile.getOrNull() + result.sharedPrecompsDir = this.getSharedPrecompsDir().asFile.getOrNull() + result.derivedDataPath = this.derivedDataPath.asFile.getOrNull() result.additionalParameters = this.additionalParameters result.devices = this.devices result.configuredDestinations = this.destinations diff --git a/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy b/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy index 64b68eab..4c47646e 100644 --- a/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/coverage/CoverageTask.groovy @@ -4,6 +4,7 @@ import org.apache.commons.io.FilenameUtils import org.apache.commons.lang.StringUtils import org.gradle.api.tasks.TaskAction import org.openbakery.AbstractXcodeTask +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.xcode.Destination class CoverageTask extends AbstractXcodeTask { @@ -48,17 +49,17 @@ class CoverageTask extends AbstractXcodeTask { def zipFilename = version + ".zip" def zip = new File(project.coverage.outputDirectory, zipFilename) def url = 'https://github.com/gcovr/gcovr/archive/' + zipFilename - ant.get(src: url, dest: project.coverage.outputDirectory, verbose:true) - ant.unzip(src: zip, dest:project.coverage.outputDirectory) + ant.get(src: url, dest: project.coverage.outputDirectory, verbose: true) + ant.unzip(src: zip, dest: project.coverage.outputDirectory) def gcovrCommand = new File(project.coverage.outputDirectory, 'gcovr-' + version + '/scripts/gcovr').absolutePath def commandList = [ - 'python', - gcovrCommand, - '-r', - '.' + 'python', + gcovrCommand, + '-r', + '.' ] String exclude = project.coverage.exclude @@ -100,9 +101,13 @@ class CoverageTask extends AbstractXcodeTask { for (Destination destination : project.coverage.testResultDestinations) { possibleDirectories.add("Build/ProfileData/" + destination.id + "/Coverage.profdata") } - + for (String directory : possibleDirectories) { - this.profileData = new File(project.xcodebuild.derivedDataPath, directory) + this.profileData = new File(project.extensions.findByType(XcodeBuildPluginExtension) + .derivedDataPath + .asFile + .getOrNull(), + directory) if (this.profileData.exists()) { return this.profileData } diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy index 2b09d4dc..a966f2fa 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy @@ -519,11 +519,11 @@ class XcodeBuildPluginExtensionSpecification extends Specification { extension.configuration = "configuration" extension.additionalParameters = "additionalParameters" - extension.dstRoot = new File(projectDir, "dstRoot") - extension.objRoot = new File(projectDir, "objRoot") - extension.symRoot = new File(projectDir, "symRoot") - extension.sharedPrecompsDir = new File(projectDir, "sharedPrecompsDir") - extension.derivedDataPath = new File(projectDir, "derivedDataPath") + extension.dstRoot.set(new File(projectDir, "dstRoot")) + extension.objRoot.set(new File(projectDir, "objRoot")) + extension.symRoot.set(new File(projectDir, "symRoot")) + extension.sharedPrecompsDir.set(new File(projectDir, "sharedPrecompsDir")) + extension.derivedDataPath.set(new File(projectDir, "derivedDataPath")) extension.arch = ['i386'] diff --git a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy index cf462311..1a31888d 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeTestRunTaskSpecification.groovy @@ -161,7 +161,7 @@ class XcodeTestRunTaskSpecification extends Specification { def "delete derivedData/Logs/Test before test is executed"() { project.xcodebuild.target = "Test" - def testDirectory = new File(project.xcodebuild.derivedDataPath, "Logs/Test") + def testDirectory = new File(project.xcodebuild.derivedDataPath.asFile.getOrNull(), "Logs/Test") FileUtils.writeStringToFile(new File(testDirectory, "foobar"), "dummy"); when: diff --git a/plugin/src/test/groovy/org/openbakery/XcodeTestTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeTestTaskSpecification.groovy index 09e4ffc6..d2c34731 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeTestTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeTestTaskSpecification.groovy @@ -518,7 +518,7 @@ class XcodeTestTaskSpecification extends Specification { mockXcodeVersion() project.xcodebuild.target = "Test" - def testDirectory = new File(project.xcodebuild.derivedDataPath, "Logs/Test") + def testDirectory = new File(project.xcodebuild.derivedDataPath.asFile.getOrNull(), "Logs/Test") FileUtils.writeStringToFile(new File(testDirectory, "foobar"), "dummy"); when: diff --git a/plugin/src/test/groovy/org/openbakery/coverage/CoverageTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/coverage/CoverageTaskSpecification.groovy index fb3f2608..63e0398d 100644 --- a/plugin/src/test/groovy/org/openbakery/coverage/CoverageTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/coverage/CoverageTaskSpecification.groovy @@ -36,7 +36,7 @@ class CoverageTaskSpecification extends Specification { def cleanup() { FileUtils.deleteDirectory(project.projectDir) - FileUtils.deleteDirectory(project.xcodebuild.derivedDataPath) + FileUtils.deleteDirectory(project.xcodebuild.derivedDataPath.asFile.getOrNull()) } @@ -116,7 +116,7 @@ class CoverageTaskSpecification extends Specification { coverageTask.binary = createFile("MyApp") coverageTask.report.commandRunner = Mock(org.openbakery.coverage.command.CommandRunner) - File profData = new File(project.xcodebuild.derivedDataPath, "Build/Intermediates/CodeCoverage/MyApp/Coverage.profdata") + File profData = new File(project.xcodebuild.derivedDataPath.asFile.getOrNull(), "Build/Intermediates/CodeCoverage/MyApp/Coverage.profdata") FileUtils.writeStringToFile(profData, "Dummy") when: @@ -135,7 +135,7 @@ class CoverageTaskSpecification extends Specification { destination.setId("MyAppID") project.coverage.setTestResultDestinations([destination]) - File profData = new File(project.xcodebuild.derivedDataPath, "Build/ProfileData/MyAppID/Coverage.profdata") + File profData = new File(project.xcodebuild.derivedDataPath.asFile.getOrNull(), "Build/ProfileData/MyAppID/Coverage.profdata") FileUtils.writeStringToFile(profData, "Dummy") when: @@ -172,7 +172,7 @@ class CoverageTaskSpecification extends Specification { coverageTask = localProject.getTasks().getByPath('coverage') coverageTask.report.commandRunner = Mock(org.openbakery.coverage.command.CommandRunner) - File profData = new File(localProject.xcodebuild.derivedDataPath, "Build/Intermediates/CodeCoverage/ExampleWatchkit/Coverage.profdata") + File profData = new File(localProject.xcodebuild.derivedDataPath.asFile.getOrNull(), "Build/Intermediates/CodeCoverage/ExampleWatchkit/Coverage.profdata") FileUtils.writeStringToFile(profData, "Dummy") when: @@ -328,7 +328,7 @@ class CoverageTaskSpecification extends Specification { coverageTask.binary = createFile("MyApp") coverageTask.report.commandRunner = Mock(org.openbakery.coverage.command.CommandRunner) - File profData = new File(project.xcodebuild.derivedDataPath, "Build/Intermediates/CodeCoverage/Coverage.profdata") + File profData = new File(project.xcodebuild.derivedDataPath.asFile.getOrNull(), "Build/Intermediates/CodeCoverage/Coverage.profdata") FileUtils.writeStringToFile(profData, "Dummy") when: diff --git a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy index cbdd1f9a..66dbb2db 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/SigningSpecification.groovy @@ -5,7 +5,9 @@ import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.rules.ExpectedException import org.junit.rules.TemporaryFolder +import org.openbakery.CommandRunner import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.XcodePlugin import org.openbakery.codesign.CodesignParameters import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.extension.Signing @@ -31,9 +33,9 @@ class SigningSpecification extends Specification { project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin + project.apply plugin: XcodePlugin - signing = new Signing(project) + signing = new Signing(project, new CommandRunner()) this.signingExtension = project.extensions .findByType(XcodeBuildPluginExtension) diff --git a/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy b/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy index e65a7bab..f1410eac 100644 --- a/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/xcode/DestinationResolverSpecification.groovy @@ -5,6 +5,7 @@ import org.gradle.testfixtures.ProjectBuilder import org.junit.Rule import org.junit.rules.ExpectedException import org.junit.rules.TemporaryFolder +import org.openbakery.CommandRunner import org.openbakery.XcodeBuildPluginExtension import org.openbakery.XcodePlugin import org.openbakery.simulators.SimulatorControl @@ -28,7 +29,7 @@ class DestinationResolverSpecification extends Specification { def setup() { project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() project.apply plugin: XcodePlugin - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, new CommandRunner()) simulatorControl = new SimulatorControlStub("simctl-list-xcode7_1.txt") destinationResolver = new DestinationResolver(simulatorControl) } @@ -44,7 +45,7 @@ class DestinationResolverSpecification extends Specification { def "XcodebuildParameters are created with iOS destination"() { when: Project project = ProjectBuilder.builder().build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, new CommandRunner()) extension.type = Type.iOS extension.destination = ['iPad 2'] @@ -52,13 +53,10 @@ class DestinationResolverSpecification extends Specification { def destinations = destinationResolver.getDestinations(parameters) then: - destinations.size() == 1 destinations[0].name == "iPad 2" - } - def "test configured devices only should add most recent runtime"() { when: extension.destination = ['iPad 2'] @@ -71,7 +69,6 @@ class DestinationResolverSpecification extends Specification { destinations[0].os == "9.1" } - def "available destinations default xcode 7"() { when: destinationResolver.simulatorControl = new SimulatorControlStub("simctl-list-xcode7.txt"); @@ -82,7 +79,6 @@ class DestinationResolverSpecification extends Specification { } - def "available destinations default"() { when: @@ -90,7 +86,6 @@ class DestinationResolverSpecification extends Specification { then: destinations.size() == 22 - } def "available destinations default for 9.1 SDK"() { @@ -99,7 +94,6 @@ class DestinationResolverSpecification extends Specification { } when: - def destinations = destinationResolver.getDestinations(extension.getXcodebuildParameters()) then: @@ -107,9 +101,7 @@ class DestinationResolverSpecification extends Specification { } - def "available destinations match"() { - extension.destination { platform = 'iOS Simulator' name = 'iPad Air' @@ -121,10 +113,8 @@ class DestinationResolverSpecification extends Specification { then: destinations.size() == 1 - } - def "available destinations not match"() { given: extension.destination { @@ -152,7 +142,6 @@ class DestinationResolverSpecification extends Specification { destinations.size() == 1 destinations[0].name == "iPad Air" destinations[0].os == "9.1" - } def "available destinations match simple multiple"() { @@ -165,10 +154,8 @@ class DestinationResolverSpecification extends Specification { then: destinations.size() == 2 - } - def "set destinations twice"() { given: @@ -181,7 +168,6 @@ class DestinationResolverSpecification extends Specification { then: destinations.size() == 2 destinations[1].name == 'iPhone 4s' - } def "resolves tvOS destination from the name"() { @@ -209,7 +195,6 @@ class DestinationResolverSpecification extends Specification { destinations[0].name == "Apple TV 1080p" } - def "resolve iPad Pro (12.9 inch)"() { given: simulatorControl = new SimulatorControlStub("simctl-list-xcode8.txt") @@ -223,8 +208,5 @@ class DestinationResolverSpecification extends Specification { destinations.size() == 1 destinations[0].name == 'iPad Pro (12.9 inch)' destinations[0].id == 'C538D7F8-E581-44FF-9B17-5391F84642FB' - - } - } From 9c12828be8047cf4ba9c54a27ad95fa64fcdee28 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 12:39:27 +0100 Subject: [PATCH 107/121] Cleanup --- ...visioningProfileReaderSpecification.groovy | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy index 12a84bc8..6b7644c7 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningProfileReaderSpecification.groovy @@ -5,6 +5,8 @@ import org.apache.commons.io.FileUtils import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import org.openbakery.CommandRunner +import org.openbakery.XcodeBuildPluginExtension +import org.openbakery.XcodePlugin import org.openbakery.codesign.ProvisioningProfileReader import org.openbakery.configuration.ConfigurationFromMap import org.openbakery.configuration.ConfigurationFromPlist @@ -28,12 +30,13 @@ class ProvisioningProfileReaderSpecification extends Specification { File appDirectory CommandRunner commandRunner = Mock(CommandRunner) PlistHelper plistHelper + XcodeBuildPluginExtension extension def setup() { projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin + project.apply plugin: XcodePlugin project.xcodebuild.infoPlist = 'Info.plist' project.xcodebuild.productName = 'Example' project.xcodebuild.productType = 'app' @@ -43,7 +46,10 @@ class ProvisioningProfileReaderSpecification extends Specification { packageTask = project.getTasks().getByPath(PackageLegacyTask.NAME) - buildOutputDirectory = new File(project.xcodebuild.symRoot, project.xcodebuild.configuration) + extension = project.extensions.findByType(XcodeBuildPluginExtension) + + + buildOutputDirectory = new File(extension.symRoot.asFile.get(), extension.configuration) buildOutputDirectory.mkdirs() appDirectory = new File(buildOutputDirectory, "Example.app") @@ -92,19 +98,15 @@ class ProvisioningProfileReaderSpecification extends Specification { } def "read Mac Provisioning Profile"() { - given: File wildcardMacProfile = new File("src/test/Resource/test-wildcard-mac-development.provisionprofile") when: ProvisioningProfileReader provisioningProfileReader = new ProvisioningProfileReaderIgnoreExpired(wildcardMacProfile, new CommandRunner()) - - def applicationIdentifier = provisioningProfileReader.getApplicationIdentifier() + String applicationIdentifier = provisioningProfileReader.getApplicationIdentifier() then: - assertThat(applicationIdentifier, is(equalTo("*"))) - } def "extract Entitlements has nothing to extract"() { @@ -123,8 +125,6 @@ class ProvisioningProfileReaderSpecification extends Specification { expect: // no exception should be thrown! reader.extractEntitlements(entitlementsFile, "org.openbakery.test.Example", null, null) - - } def "extract Entitlements"() { @@ -182,7 +182,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlements.getString("com..apple..application-identifier") == "Z7L2YCUH45.org.openbakery.test.Example" } - def "extract Entitlements with keychain access group"() { given: String expectedContents = "\n" + @@ -258,7 +257,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlements.getList("keychain-access-groups").contains("AAAAAAAAAA.com.example.Test") } - def "extract Entitlements test application identifier"() { given: File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -283,7 +281,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlementsFile.text.contains("CCCCCCCCCC.com.example.Test") } - String getEntitlementWithApplicationIdentifier(String applicationIdentifier) { return "\n" + "\n" + @@ -327,7 +324,6 @@ class ProvisioningProfileReaderSpecification extends Specification { thrown(IllegalStateException.class) } - def "extract Entitlements with wildcard application identifier"() { given: File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -351,7 +347,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "extract Entitlements with wildcard application identifier that does match"() { given: File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -373,7 +368,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlementsFile.text.contains("AAAAAAAAAAA.org.openbakery.test.Example.widget") } - def "is ad-hoc profile"() { when: ProvisioningProfileReader reader = new ProvisioningProfileReader(new File("../libtest/src/main/Resource/test.mobileprovision"), new CommandRunner()) @@ -382,7 +376,6 @@ class ProvisioningProfileReaderSpecification extends Specification { reader.isAdHoc() == true } - def "is not ad-hoc profile"() { when: ProvisioningProfileReader reader = new ProvisioningProfileReader(new File("../libtest/src/main/Resource/Appstore.mobileprovision"), new CommandRunner()) @@ -391,7 +384,6 @@ class ProvisioningProfileReaderSpecification extends Specification { reader.isAdHoc() == false } - def "extract Entitlements with wildcard and kvstore should start with team id"() { given: File mobileprovision = new File("src/test/Resource/openbakery-team.mobileprovision") @@ -434,7 +426,6 @@ class ProvisioningProfileReaderSpecification extends Specification { plistHelper.getValueFromPlist(entitlementsFile, "com.apple.developer.ubiquity-container-identifiers").startsWith("XXXXXZZZZZ.") } - def "get provisioning profile from plist"() { def commandList @@ -453,7 +444,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "provisioning match"() { given: File appMobileprovision = new File("../libtest/src/main/Resource/test.mobileprovision") @@ -475,7 +465,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "provisioning Match more"() { given: File appMobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -494,7 +483,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def "extract Entitlements and merge Example.entitlements"() { given: File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -518,7 +506,6 @@ class ProvisioningProfileReaderSpecification extends Specification { } - def setupForEntitlementTest(Map data) { File mobileprovision = new File("src/test/Resource/openbakery.mobileprovision") @@ -534,7 +521,6 @@ class ProvisioningProfileReaderSpecification extends Specification { return destinationFile } - def "extract Entitlements and replace com.apple.developer.icloud-container-identifiers"() { given: Map data = ["com.apple.developer.icloud-container-identifiers": ["iCloud.com.example.Test"]] @@ -548,7 +534,6 @@ class ProvisioningProfileReaderSpecification extends Specification { entitlements.getList("com..apple..developer..icloud-container-identifiers").contains("iCloud.com.example.Test") } - def "extract Entitlements and replace ubiquity-container-identifiers"() { given: Map data = ["com.apple.developer.ubiquity-container-identifiers": ["com.example.Test"]] From 9b6460bab4e9fd669bc16d278fabbdcbd1231e91 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 12:42:27 +0100 Subject: [PATCH 108/121] Fix the SimulatorInstallAppTaskSpecification --- ...imulatorInstallAppTaskSpecification.groovy | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorInstallAppTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorInstallAppTaskSpecification.groovy index 9e675274..37a4c610 100644 --- a/plugin/src/test/groovy/org/openbakery/simulators/SimulatorInstallAppTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/simulators/SimulatorInstallAppTaskSpecification.groovy @@ -7,25 +7,20 @@ import org.openbakery.codesign.Codesign import org.openbakery.xcode.Type import spock.lang.Specification -/** - * Created by rene on 27.03.17. - */ class SimulatorInstallAppTaskSpecification extends Specification { - SimulatorInstallAppTask task Project project File projectDir def setup() { - projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - project.apply plugin: org.openbakery.XcodePlugin + project.apply plugin: XcodePlugin task = project.tasks.findByName(XcodePlugin.SIMULATORS_INSTALL_APP_TASK_NAME) - } + def "create"() { expect: task instanceof SimulatorInstallAppTask @@ -34,7 +29,8 @@ class SimulatorInstallAppTaskSpecification extends Specification { def "depends on"() { when: - def dependsOn = task.getDependsOn() + def dependsOn = task.getDependsOn() + then: dependsOn.size() == 2 dependsOn.contains(XcodePlugin.XCODE_BUILD_TASK_NAME) @@ -53,7 +49,9 @@ class SimulatorInstallAppTaskSpecification extends Specification { task.run() then: - 1* simulatorControl.simctl(["install", "booted", project.xcodebuild.applicationBundle.absolutePath]) + 1 * simulatorControl.simctl(["install", + "booted", + project.xcodebuild.applicationBundle.absolutePath]) } def "codesign is not null"() { @@ -77,8 +75,7 @@ class SimulatorInstallAppTaskSpecification extends Specification { Codesign codesign = Mock(Codesign) task.codesign = codesign - SimulatorControl simulatorControl = Mock(SimulatorControl) - task.simulatorControl = simulatorControl + task.simulatorControl = Mock(SimulatorControl) project.xcodebuild.bundleName = "MyApp" @@ -88,7 +85,4 @@ class SimulatorInstallAppTaskSpecification extends Specification { then: 1 * codesign.sign(project.xcodebuild.applicationBundle) } - - - } From 8dacb1f69fccdf707f30a595a1146720be4bb35d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Fri, 18 May 2018 15:07:25 +0100 Subject: [PATCH 109/121] Fix unit tests --- .../XcodeBuildPluginExtension.groovy | 2 +- ...AbstractXcodeBuildTaskSpecification.groovy | 24 ++-- ...deBuildPluginExtensionSpecification.groovy | 106 +++++------------- ...isioningInstallTaskOSXSpecification.groovy | 15 +-- 4 files changed, 48 insertions(+), 99 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 2f48c798..4823ee50 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -425,7 +425,7 @@ class XcodeBuildPluginExtension { result.additionalParameters = this.additionalParameters result.devices = this.devices result.configuredDestinations = this.destinations - result.bitcode = this.bitcode.getOrElse(false) + result.bitcode = this.bitcode.getOrElse(true) result.applicationBundle = getApplicationBundle() if (this.arch != null) { diff --git a/plugin/src/test/groovy/org/openbakery/AbstractXcodeBuildTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/AbstractXcodeBuildTaskSpecification.groovy index fb6e3170..c82a991a 100644 --- a/plugin/src/test/groovy/org/openbakery/AbstractXcodeBuildTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/AbstractXcodeBuildTaskSpecification.groovy @@ -8,27 +8,27 @@ import spock.lang.Specification class AbstractXcodeBuildTaskSpecification extends Specification { - Project project AbstractXcodeBuildTask xcodeBuildTask File projectDir - - + XcodeBuildPluginExtension extension def setup() { projectDir = new File(System.getProperty("java.io.tmpdir"), "gradle-xcodebuild") project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.buildDir = new File('build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin + project.apply plugin: XcodePlugin xcodeBuildTask = project.getTasks().getByPath(XcodePlugin.XCODE_BUILD_TASK_NAME) + + extension = project.extensions + .getByType(XcodeBuildPluginExtension) } def cleanup() { - FileUtils.deleteDirectory(project.projectDir) + FileUtils.deleteDirectory(project.projectDir) } - def "test get identity when is set manually"() { when: project.xcodebuild.signing.identity = "my identity" @@ -37,7 +37,6 @@ class AbstractXcodeBuildTaskSpecification extends Specification { xcodeBuildTask.getSigningIdentity() == "my identity" } - def "security is initialized"() { expect: xcodeBuildTask.security != null @@ -48,12 +47,12 @@ class AbstractXcodeBuildTaskSpecification extends Specification { given: File keychain = new File(projectDir, "my.keychain") FileUtils.writeStringToFile(keychain, "dummy") - project.xcodebuild.signing.keychain = keychain - project.xcodebuild.signing.identity = null + extension.signing.keychain = keychain + extension.signing.identity = null when: Security security = Mock(Security) - security.getIdentity(project.xcodebuild.signing.getKeychainPathInternal()) >> "my identity from security" + security.getIdentity(extension.signing.getKeychainPathInternal()) >> "my identity from security" xcodeBuildTask.security = security then: @@ -65,11 +64,10 @@ class AbstractXcodeBuildTaskSpecification extends Specification { def "test get identity null and keychain does not exist should return null"() { when: - project.xcodebuild.signing.identity = null - project.xcodebuild.signing.keychain = new File("my.keychain") + extension.signing.identity = null + extension.signing.keychain = new File("my.keychain") then: xcodeBuildTask.getSigningIdentity() == null } - } diff --git a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy index a966f2fa..8e2bbb09 100644 --- a/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/XcodeBuildPluginExtensionSpecification.groovy @@ -29,8 +29,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { project = ProjectBuilder.builder().withProjectDir(projectDir).build() project.apply plugin: org.openbakery.XcodePlugin - extension = new XcodeBuildPluginExtension(project) - extension.commandRunner = commandRunner + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.infoPlist = "Info.plist"; @@ -154,7 +153,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/iOS/Example") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() extension.type = Type.iOS @@ -176,8 +175,8 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/iOS/Example") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) - extension.commandRunner = new CommandRunner() + extension = new XcodeBuildPluginExtension(project, commandRunner) + XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() @@ -198,8 +197,8 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/tvOS/Example_tvOS_Swift") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) - extension.commandRunner = new CommandRunner() + extension = new XcodeBuildPluginExtension(project, commandRunner) + XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example_tvOS_Swift.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() @@ -216,12 +215,11 @@ class XcodeBuildPluginExtensionSpecification extends Specification { } - def "application bundle for watchos"() { - when: - + def "application bundle for ios"() { + setup: File projectDir = new File("../example/iOS/ExampleWatchkit") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.projectSettings = createProjectSettings() extension.type = Type.iOS extension.target = "ExampleWatchkit WatchKit App" @@ -230,21 +228,20 @@ class XcodeBuildPluginExtensionSpecification extends Specification { extension.productType = "app" extension.infoPlist = "../../example/iOS/ExampleWatchkit/ExampleWatchkit WatchKit App/Info.plist" - - String applicationBundle = extension.getApplicationBundle().absolutePath; + when: + String applicationBundle = extension.getApplicationBundle().absolutePath then: - applicationBundle.endsWith("build/sym/Debug-iphoneos/ExampleWatchkit.app") - + applicationBundle.endsWith("build/sym/Debug-iphoneos/ExampleWatchkit WatchKit App.app") } def "application bundle for watch find parent"() { when: File projectDir = new File("../example/iOS/ExampleWatchkit") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.projectSettings = createProjectSettings() - extension.type = Type.iOS + extension.type = Type.watchOS extension.target = "ExampleWatchkit WatchKit App" extension.simulator = false @@ -252,11 +249,9 @@ class XcodeBuildPluginExtensionSpecification extends Specification { BuildConfiguration parent = extension.getParent(extension.projectSettings["ExampleWatchkit WatchKit App"].buildSettings["Debug"]) then: - parent.bundleIdentifier == "org.openbakery.test.Example" + parent.bundleIdentifier == "org.openbakery.test.Example.watchkitapp" } - - void mockValueFromPlist(String key, String value) { PlistHelperStub plistHelperStub = new PlistHelperStub() File infoPlist = new File(project.projectDir, "Info.plist") @@ -418,7 +413,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/iOS/Example") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() extension.type = Type.iOS @@ -436,7 +431,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/tvOS/Example_tvOS_Swift") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "Example_tvOS_Swift.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() extension.type = Type.tvOS @@ -454,7 +449,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/OSX/ExampleOSX") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) XcodeProjectFile xcodeProjectFile = new XcodeProjectFile(project, new File(projectDir, "ExampleOSX.xcodeproj/project.pbxproj")) extension.projectSettings = xcodeProjectFile.getProjectSettings() extension.type = Type.macOS @@ -472,7 +467,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/iOS/Example") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) then: extension.projectFile.canonicalFile == new File("../example/iOS/Example/Example.xcodeproj").canonicalFile @@ -483,7 +478,7 @@ class XcodeBuildPluginExtensionSpecification extends Specification { setup: File projectDir = new File(".") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) when: File missingFile = extension.projectFile @@ -497,64 +492,19 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/iOS") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.projectFile = "Example/Example.xcodeproj" then: extension.projectFile.canonicalFile == new File("../example/iOS/Example/Example.xcodeproj").canonicalFile } - - def "XcodebuildParameters are created with proper values"() { - when: - File projectDir = new File("../example/macOS/ExampleOSX") - project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) - extension.type = Type.macOS - extension.simulator = false - extension.target = "ExampleOSX" - extension.scheme.set("ExampleScheme") - - extension.workspace = "workspace" - extension.configuration = "configuration" - extension.additionalParameters = "additionalParameters" - - extension.dstRoot.set(new File(projectDir, "dstRoot")) - extension.objRoot.set(new File(projectDir, "objRoot")) - extension.symRoot.set(new File(projectDir, "symRoot")) - extension.sharedPrecompsDir.set(new File(projectDir, "sharedPrecompsDir")) - extension.derivedDataPath.set(new File(projectDir, "derivedDataPath")) - extension.arch = ['i386'] - - - def parameters = extension.getXcodebuildParameters() - - then: - parameters.type == Type.macOS - parameters.simulator == false - parameters.target == "ExampleOSX" - parameters.scheme == "ExampleScheme" - parameters.workspace == "workspace" - parameters.configuration == "configuration" - parameters.additionalParameters == "additionalParameters" - parameters.dstRoot.canonicalPath == new File(projectDir, "dstRoot").canonicalPath - parameters.objRoot.canonicalPath == new File(projectDir, "objRoot").canonicalPath - parameters.symRoot.canonicalPath == new File(projectDir, "symRoot").canonicalPath - parameters.sharedPrecompsDir.canonicalPath == new File(projectDir, "sharedPrecompsDir").canonicalPath - parameters.derivedDataPath.canonicalPath == new File(projectDir, "derivedDataPath").canonicalPath - - parameters.arch.size() == 1 - parameters.arch[0] == "i386" - - parameters.devices == Devices.UNIVERSAL - } - def "XcodebuildParameters get workspace from project"() { when: File projectDir = new File("../example/iOS/SwiftExample") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.type = Type.iOS workspaceDirectory = new File(projectDir, "SwiftExample.xcworkspace") @@ -569,14 +519,14 @@ class XcodeBuildPluginExtensionSpecification extends Specification { def "bitcode is default false"() { expect: - extension.bitcode == false + extension.bitcode.get() == false } def "xcodeparameter is created with simulator true value"() { when: File projectDir = new File("../example/macOS/ExampleOSX") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.simulator = true then: @@ -587,18 +537,18 @@ class XcodeBuildPluginExtensionSpecification extends Specification { when: File projectDir = new File("../example/macOS/ExampleOSX") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) - extension.bitcode = true + extension = new XcodeBuildPluginExtension(project, commandRunner) + extension.bitcode.set(true) then: - extension.getXcodebuildParameters().bitcode == true + extension.getXcodebuildParameters().bitcode } def "xcodebuildParameters is created with the applicationBundle"() { when: File projectDir = new File("../example/macOS/ExampleOSX") project = ProjectBuilder.builder().withProjectDir(projectDir).build() - extension = new XcodeBuildPluginExtension(project) + extension = new XcodeBuildPluginExtension(project, commandRunner) extension.bundleName = "MyApp" then: diff --git a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy index 8a5777aa..50078200 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/ProvisioningInstallTaskOSXSpecification.groovy @@ -29,9 +29,10 @@ class ProvisioningInstallTaskOSXSpecification extends Specification { project.xcodebuild.type = Type.macOS - provisioningInstallTask = project.getTasks().getByPath(ProvisioningInstallTask.TASK_NAME) + provisioningInstallTask = project.getTasks() + .getByPath(ProvisioningInstallTask.TASK_NAME) - provisioningInstallTask.commandRunner = commandRunner + provisioningInstallTask.commandRunnerProperty.set(commandRunner) provisionLibraryPath = new File(System.getProperty("user.home") + "/Library/MobileDevice/Provisioning Profiles/"); @@ -48,21 +49,21 @@ class ProvisioningInstallTaskOSXSpecification extends Specification { File testMobileprovision = new File("src/test/Resource/test-wildcard-mac.provisionprofile") project.xcodebuild.signing.mobileProvisionURI = testMobileprovision.toURI().toString() - ProvisioningProfileReader provisioningProfileIdReader = new ProvisioningProfileReader(testMobileprovision, commandRunner) - String uuid = provisioningProfileIdReader.getUUID() + ProvisioningProfileReader reader = new ProvisioningProfileReader(testMobileprovision, commandRunner) + String uuid = reader.getUUID() String name = "gradle-" + uuid + ".provisionprofile"; File source = new File(projectDir, "build/provision/" + name) File destination = new File(provisionLibraryPath, name) when: - provisioningInstallTask.install() + provisioningInstallTask.download() File sourceFile = new File(projectDir, "build/provision/" + name) then: sourceFile.exists() - 1 * commandRunner.run(["/bin/ln", "-s", source.absolutePath , destination.absolutePath]) + 1 * commandRunner.run(["/bin/ln", "-s", source.absolutePath, destination.absolutePath]) } def "multiple ProvisioningProfiles"() { @@ -84,7 +85,7 @@ class ProvisioningInstallTaskOSXSpecification extends Specification { File secondDestination = new File(provisionLibraryPath, secondName) when: - provisioningInstallTask.install() + provisioningInstallTask.download() then: firstFile.exists() From e167ce07119e752a2bdb29f45f8c1fce29a4fbdd Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 24 May 2018 09:31:49 -0400 Subject: [PATCH 110/121] --wip-- [skip ci] --- .../codesign/ProvisioningProfileReader.groovy | 9 +- .../xcode/DestinationResolver.groovy | 2 - ...PrepareXcodeArchivingFunctionalTest.groovy | 2 +- .../PrepareXcodeArchivingTask.groovy | 14 +-- .../groovy/org/openbakery/XcodePlugin.groovy | 11 +- .../org/openbakery/extension/Signing.groovy | 34 +----- .../packaging/PackageTaskIosAndTvOS.groovy | 4 + .../signing/KeychainCreateTask.groovy | 111 ++++++++++++++---- .../signing/ProvisioningInstallTask.groovy | 4 + .../simulators/AbstractSimulatorTask.groovy | 5 +- .../org/openbakery/util/FileUtil.groovy | 4 + .../KeychainCreateTaskSpecification.groovy | 8 +- 12 files changed, 137 insertions(+), 71 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy index 3f62a32a..121b6cc8 100644 --- a/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy +++ b/libxcode/src/main/groovy/org/openbakery/codesign/ProvisioningProfileReader.groovy @@ -69,7 +69,10 @@ class ProvisioningProfileReader { checkExpired() } - static File getProvisionFileForIdentifier(String bundleIdentifier, List mobileProvisionFiles, CommandRunner commandRunner, PlistHelper plistHelper) { + static File getProvisionFileForIdentifier(String bundleIdentifier, + List mobileProvisionFiles, + CommandRunner commandRunner, + PlistHelper plistHelper) { def provisionFileMap = [:] for (File mobileProvisionFile : mobileProvisionFiles) { @@ -99,8 +102,8 @@ class ProvisioningProfileReader { } } - logger.info("No provisioning profile found for bundle identifier {}", bundleIdentifier) - logger.info("Available bundle identifier are {}" + provisionFileMap.keySet()) + logger.warn("No provisioning profile found for bundle identifier {}", bundleIdentifier) + logger.warn("Available bundle identifier are {}" + provisionFileMap.keySet()) return null } diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy index 870cc36f..be14a92f 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/DestinationResolver.groovy @@ -36,10 +36,8 @@ class DestinationResolver { def runtime = simulatorControl.getMostRecentRuntime(parameters.type) - if (isSimulatorFor(parameters)) { // filter only on simulator builds - logger.debug("is a simulator build") if (parameters.configuredDestinations != null) { diff --git a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy index 44ad243c..f1606a6d 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/PrepareXcodeArchivingFunctionalTest.groovy @@ -154,7 +154,7 @@ class PrepareXcodeArchivingFunctionalTest extends Specification { signing { certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" - entitlementsFile = project.provisioningFile1("${entitlementsFile.absolutePath}") + entitlementsFile = "${entitlementsFile.absolutePath}" } } """ diff --git a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy index dc6692dc..57364b9c 100644 --- a/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/PrepareXcodeArchivingTask.groovy @@ -27,11 +27,13 @@ class PrepareXcodeArchivingTask extends DefaultTask { final Property commandRunnerProperty = project.objects.property(CommandRunner) final Property provisioningForConfiguration = project.objects.property(File) final Property plistHelperProperty = project.objects.property(PlistHelper) - final Property provisioningReader = project.objects.property(ProvisioningProfileReader) final Property certificateFriendlyName = project.objects.property(String) final Property configurationBundleIdentifier = project.objects.property(String) final Property entitlementsFilePath = project.objects.property(String) + @Internal + final Property provisioningReader = project.objects.property(ProvisioningProfileReader) + public static final String DESCRIPTION = "Prepare the archive configuration file" public static final String NAME = "prepareArchiving" @@ -45,10 +47,10 @@ 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) - dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) - dependsOn(XcodePlugin.INFOPLIST_MODIFY_TASK_NAME) this.description = DESCRIPTION @@ -63,7 +65,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { @Override File transform(String bundleIdentifier) { return ProvisioningProfileReader.getProvisionFileForIdentifier(bundleIdentifier, - registeredProvisioningFiles.get().asList() as List, + registeredProvisioningFiles.getOrNull() as List, commandRunnerProperty.get(), plistHelperProperty.get()) } @@ -80,7 +82,6 @@ class PrepareXcodeArchivingTask extends DefaultTask { this.onlyIf { return certificateFriendlyName.present && configurationBundleIdentifier.present && - provisioningForConfiguration.present && outputFile.present && provisioningForConfiguration.present } @@ -88,7 +89,7 @@ class PrepareXcodeArchivingTask extends DefaultTask { @TaskAction void generate() { - logger.debug("Preparing archiving") + logger.info("Preparing archiving") outputFile.get().asFile.text = "" @@ -112,5 +113,4 @@ class PrepareXcodeArchivingTask extends DefaultTask { .asFile .append(System.getProperty("line.separator") + key + " = " + value) } - } diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 82a0106c..60727419 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -525,7 +525,11 @@ class XcodePlugin implements Plugin { project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) - project.task(SIMULATORS_START_TASK_NAME, type: SimulatorStartTask, group: SIMULATORS_LIST_TASK_NAME) + + project.tasks.create(SIMULATORS_START_TASK_NAME, SimulatorStartTask) { + it.group = SIMULATORS_LIST_TASK_NAME + } + project.task(SIMULATORS_RUN_APP_TASK_NAME, type: SimulatorRunAppTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_INSTALL_APP_TASK_NAME, type: SimulatorInstallAppTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_KILL_TASK_NAME, type: SimulatorKillTask, group: SIMULATORS_LIST_TASK_NAME) @@ -545,12 +549,17 @@ class XcodePlugin implements Plugin { private void configureKeychain(Project project) { project.tasks.create(KeychainCreateTask.TASK_NAME, KeychainCreateTask.class) { it.group = XCODE_GROUP_NAME + it.certificateFile.set(signingExtension.certificate) + it.certificateUri.set(signingExtension.certificateURI) it.certificatePassword.set(signingExtension.certificatePassword) it.outputDirectory.set(signingExtension.signingDestinationRoot) it.keyChainFile.set(signingExtension.keyChainFile) it.keychainTimeout.set(signingExtension.timeout) it.security.set(securityTool) + it.commandRunnerProperty.set(commandRunner) + + signingExtension.certificateFriendlyName.set(it.certificateFriendlyName) } } diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index fe9dee14..40fddbaf 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -16,8 +16,6 @@ import org.openbakery.signing.SigningMethod import org.openbakery.util.PathHelper import javax.inject.Inject -import java.util.regex.Matcher -import java.util.regex.Pattern class Signing { @@ -29,6 +27,7 @@ class Signing { final Property certificateFriendlyName = project.objects.property(String) final Property certificatePassword = project.objects.property(String) final RegularFileProperty certificate = project.layout.fileProperty() + final Property certificateURI = project.objects.property(String) final RegularFileProperty entitlementsFile = project.layout.fileProperty() final RegularFileProperty keychain = project.layout.fileProperty() final RegularFileProperty keyChainFile = project.layout.fileProperty() @@ -52,7 +51,6 @@ class Signing { String plugin public static final String KEYCHAIN_NAME_BASE = "gradle-" - private static final Pattern PATTERN = ~/^\s{4}friendlyName:\s(?[^\n]+)/ /** * internal parameters @@ -125,6 +123,10 @@ class Signing { entitlementsFile.set(new File(value)) } + void addMobileProvisionFile(File file) { + this.mobileProvisionList.add(file.toURI().toString()) + } + @Deprecated void setMobileProvisionURI(String value) { this.mobileProvisionList.add(value) @@ -132,7 +134,7 @@ class Signing { @Deprecated void setMobileProvisionURI(String... values) { - values.each { this.mobileProvisionList.add(it) } + this.mobileProvisionList.get().addAll(values.toList()) } CodesignParameters getCodesignParameters() { @@ -151,30 +153,6 @@ class Signing { return result } - String getSignatureFriendlyName(File file) { - return Optional.ofNullable(getKeyContent(file) - .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) { - return commandRunner.runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + certificatePassword.get()]) - } - @Override public String toString() { if (this.keychain != null) { diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index b666e315..88554159 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -99,7 +99,11 @@ class PackageTaskIosAndTvOS extends DefaultTask { @TaskAction private void packageArchive() { + logger.info("Packaging the archive") + + assert signingMethod.present : "Cannot package, the signing method is not defined" assert getArchiveFile().exists() && getArchiveFile().isDirectory() + generateExportOptionPlist() packageIt() } diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 7f4872c6..05d216c0 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -1,39 +1,50 @@ package org.openbakery.signing +import de.undercouch.gradle.tasks.download.Download import groovy.transform.CompileStatic -import org.gradle.api.DefaultTask +import org.apache.commons.io.FileUtils import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction -import org.openbakery.XcodeBuildPluginExtension +import org.gradle.api.tasks.* +import org.openbakery.CommandRunner import org.openbakery.codesign.Security -import org.openbakery.extension.Signing import org.openbakery.util.FileUtil import org.openbakery.util.SystemUtil import org.openbakery.xcode.Version +import java.util.regex.Matcher +import java.util.regex.Pattern + @CompileStatic -class KeychainCreateTask extends DefaultTask { +class KeychainCreateTask extends Download { @InputFile + @Optional final RegularFileProperty certificateFile = newInputFile() + @Input + @Optional + final Property certificateUri = project.objects.property(String) + @Input final Property certificatePassword = project.objects.property(String) @Input final Property keychainTimeout = project.objects.property(Integer) + final Property certificateFriendlyName = project.objects.property(String) + + final Property commandRunnerProperty = project.objects.property(CommandRunner) + @OutputFile final RegularFileProperty keyChainFile = newOutputFile() 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" @@ -44,17 +55,11 @@ class KeychainCreateTask extends DefaultTask { super() this.description = TASK_DESCRIPTION onlyIf { - XcodeBuildPluginExtension extension = project - .getExtensions() - .findByType(XcodeBuildPluginExtension) - - Signing signing = extension.signing - - if (!signing.certificate.present) { + if (!certificateFile.present && !certificateUri.present) { logger.warn("No signing certificate defined, will skip the keychain creation") } - if (!signing.certificatePassword.present) { + if (!certificatePassword.present) { logger.warn("No signing certificate password defined, will skip the keychain creation") } @@ -62,29 +67,64 @@ class KeychainCreateTask extends DefaultTask { logger.debug("Using keychain : " + keyChainFile.get()) } - return (signing.certificate.present && - signing.certificatePassword.present) || + return ((certificateFile.present || certificateUri.present) && + certificatePassword.present) || (keyChainFile.present && keyChainFile.asFile.get().exists()) } } @TaskAction - void create() { - project.gradle.buildFinished { - removeGradleKeychainsFromSearchList() - deleteTemporaryKeyChainFile() + void download() { + if (certificateUri.present) { + outputDirectory.get().asFile.mkdirs() + configureDownload() + super.download() + resolveCertificateFile() + } else { + File file = certificateFile.asFile.get() + temporaryCertificateFile = new File(outputDirectory.asFile.get(), file.name) + FileUtils.copyFile(file, temporaryCertificateFile) } + parseCertificateFile() createTemporaryCertificateFile() createKeyChainAndImportCertificate() addKeyChainToThePartitionList() setupOptionalTimeout() + + project.gradle.buildFinished { + removeGradleKeychainsFromSearchList() + deleteTemporaryKeyChainFile() + } + } + + private void configureDownload() { + this.src(certificateUri.get()) + this.dest(outputDirectory.get().asFile) + this.acceptAnyCertificate(true) + } + + private void resolveCertificateFile() { + temporaryCertificateFile = getOutputFiles().first() + } + + private void parseCertificateFile() { + certificateFriendlyName.set(getSignatureFriendlyName()) + + // Delete on exit the downloaded files + project.gradle.buildFinished { + if (temporaryCertificateFile.exists()) { + temporaryCertificateFile.delete() + } + } } private void createTemporaryCertificateFile() { temporaryCertificateFile = FileUtil.download(project, outputDirectory.asFile.get(), - certificateFile.asFile.get().toURI().toString()) + certificateUri.present + ? certificateUri.get() + : certificateFile.asFile.get().toURI().toString()) // Delete the temporary file on completion project.gradle.buildFinished { @@ -155,4 +195,29 @@ class KeychainCreateTask extends DefaultTask { 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) { + return commandRunnerProperty.get() + .runWithResult(["openssl", + "pkcs12", + "-nokeys", + "-in", + file.absolutePath, + "-passin", + "pass:" + certificatePassword.get()]) + } } diff --git a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy index 34cc4566..92d913fb 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/ProvisioningInstallTask.groovy @@ -70,6 +70,10 @@ class ProvisioningInstallTask extends Download { PROVISIONING_DIR.mkdirs() File destinationFile = new File(PROVISIONING_DIR, provisioningFile.getFormattedName()) + if (destinationFile.exists()) { + destinationFile.delete() + } + FileUtils.copyFile(provisioningFile.getFile(), destinationFile) return destinationFile } diff --git a/plugin/src/main/groovy/org/openbakery/simulators/AbstractSimulatorTask.groovy b/plugin/src/main/groovy/org/openbakery/simulators/AbstractSimulatorTask.groovy index 6405f3fc..b16bf6a3 100644 --- a/plugin/src/main/groovy/org/openbakery/simulators/AbstractSimulatorTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/simulators/AbstractSimulatorTask.groovy @@ -11,9 +11,10 @@ class AbstractSimulatorTask extends AbstractXcodeTask { Destination getDestination() { - return getDestinationResolver().getDestinations(project.xcodebuild.getXcodebuildParameters()).first() + return getDestinationResolver() + .getDestinations(project.xcodebuild.getXcodebuildParameters()) + .first() } - } diff --git a/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy b/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy index c8b55be6..dda3590a 100644 --- a/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy +++ b/plugin/src/main/groovy/org/openbakery/util/FileUtil.groovy @@ -30,4 +30,8 @@ class FileUtil { File file = new File(toDirectory, FilenameUtils.getName(address)) return file } + + static boolean isLocalFile(String uri) { + return new File(new URI(uri)).exists() + } } diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy index 66290e0e..7915d024 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy @@ -75,7 +75,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.create() + keychainCreateTask.download() then: "The `setPartitionList` method should be call only for OS version > 10.12" 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), @@ -105,7 +105,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.create() + keychainCreateTask.download() then: "The `setPartitionList` method should be call only for OS version > 10.12" 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), @@ -136,7 +136,7 @@ class KeychainCreateTaskSpecification extends Specification { xcodeBuildPluginExtension.signing.timeout.set(timeout) when: - keychainCreateTask.create() + keychainCreateTask.download() then: count * mockSecurity.setTimeout(timeout, @@ -154,7 +154,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.create() + keychainCreateTask.download() then: File file = xcodeBuildPluginExtension.signing From ec9a7d0020fc04a2683874cd9a64956205d31859 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 24 May 2018 10:20:18 -0400 Subject: [PATCH 111/121] --wip-- [skip ci] --- .../packaging/PackageTaskIosAndTvOS.groovy | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 88554159..00133ba1 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -7,7 +7,6 @@ import org.gradle.api.Task import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import org.gradle.api.specs.Spec import org.gradle.api.tasks.* import org.openbakery.CommandRunner import org.openbakery.XcodePlugin @@ -64,12 +63,9 @@ class PackageTaskIosAndTvOS extends DefaultTask { dependsOn(ProvisioningInstallTask.TASK_NAME) dependsOn(XcodePlugin.XCODE_CONFIG_TASK_NAME) - onlyIf(new Spec() { - @Override - boolean isSatisfiedBy(Task task) { - return buildType.get() == Type.iOS || - buildType.get() == Type.tvOS - } + onlyIf({ Task task -> + return buildType.get() == Type.iOS || + buildType.get() == Type.tvOS }) } @@ -101,7 +97,7 @@ class PackageTaskIosAndTvOS extends DefaultTask { private void packageArchive() { logger.info("Packaging the archive") - assert signingMethod.present : "Cannot package, the signing method is not defined" + assert signingMethod.present: "Cannot package, the signing method is not defined" assert getArchiveFile().exists() && getArchiveFile().isDirectory() generateExportOptionPlist() From be37cf2042909e0a4520a5d91126260e5f5e839e Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 29 May 2018 04:13:00 -0400 Subject: [PATCH 112/121] Fixing unit tests and adjustements --- .../org/openbakery/xcode/Xcodebuild.groovy | 18 ++++++------- .../org/openbakery/extension/Signing.groovy | 9 ------- .../openbakery/packaging/PackageTask.groovy | 4 +-- .../packaging/PackageTaskIosAndTvOS.groovy | 1 - .../signing/KeychainCreateTask.groovy | 25 +++++++++++------ .../KeychainCreateTaskSpecification.groovy | 27 ++++++++++++------- 6 files changed, 45 insertions(+), 39 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy index 48a4d2a7..b84bae48 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcodebuild.groovy @@ -47,10 +47,10 @@ class Xcodebuild { } } - public static void packageIpa(CommandRunner commandRunner, - File archivePath, - File exportPath, - File exportOptionsPlist) { + static void packageIpa(CommandRunner commandRunner, + File archivePath, + File exportPath, + File exportOptionsPlist) { assert archivePath != null && archivePath.exists() assert exportPath != null && exportPath.exists() @@ -63,11 +63,11 @@ class Xcodebuild { ARGUMENT_EXPORT_OPTIONS_PLIST, exportOptionsPlist.absolutePath) } - public static void archive(CommandRunner commandRunner, - String scheme, - File outputPath, - File xcConfig, - @Nullable File xcodeApp) { + static void archive(CommandRunner commandRunner, + String scheme, + File outputPath, + File xcConfig, + @Nullable File xcodeApp) { assert scheme != null assert xcConfig.exists() && !xcConfig.isDirectory() diff --git a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy index 40fddbaf..6d93319a 100644 --- a/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy +++ b/plugin/src/main/groovy/org/openbakery/extension/Signing.groovy @@ -1,9 +1,7 @@ package org.openbakery.extension import org.gradle.api.Project -import org.gradle.api.Transformer import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFile import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property @@ -64,15 +62,8 @@ class Signing { this.commandRunner = commandRunner this.project = project - this.signingDestinationRoot.set(project.layout.buildDirectory.dir("codesign")) this.provisioningDestinationRoot.set(project.layout.buildDirectory.dir("provision")) - this.certificateFriendlyName.set(certificate.map(new Transformer() { - @Override - String transform(RegularFile regularFile) { - return getSignatureFriendlyName(regularFile.asFile) - } - })) this.keyChainFile.set(signingDestinationRoot.file(KEYCHAIN_NAME_BASE + System.currentTimeMillis() diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy index 1a2553b9..a51a5df9 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy @@ -1,8 +1,8 @@ package org.openbakery.packaging -import org.openbakery.AbstractXcodeBuildTask +import org.gradle.api.DefaultTask -class PackageTask extends AbstractXcodeBuildTask { +class PackageTask extends DefaultTask { public static final String NAME = "package" diff --git a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy index 00133ba1..5f13fdc6 100644 --- a/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy +++ b/plugin/src/main/groovy/org/openbakery/packaging/PackageTaskIosAndTvOS.groovy @@ -164,5 +164,4 @@ class PackageTaskIosAndTvOS extends DefaultTask { getOutputDirectory(), getExportOptionsPlistFile()) } - } diff --git a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy index 05d216c0..51d46b5b 100644 --- a/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/signing/KeychainCreateTask.groovy @@ -8,6 +8,7 @@ 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.SystemUtil @@ -211,13 +212,21 @@ class KeychainCreateTask extends Download { } private String getKeyContent(File file) { - return commandRunnerProperty.get() - .runWithResult(["openssl", - "pkcs12", - "-nokeys", - "-in", - file.absolutePath, - "-passin", - "pass:" + certificatePassword.get()]) + 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 } } diff --git a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy index 7915d024..af4bb901 100644 --- a/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy +++ b/plugin/src/test/groovy/org/openbakery/signing/KeychainCreateTaskSpecification.groovy @@ -20,8 +20,9 @@ class KeychainCreateTaskSpecification extends Specification { @Rule final TemporaryFolder tmpDirectory = new TemporaryFolder() + KeychainCreateTask subject + Project project - KeychainCreateTask keychainCreateTask CommandRunner commandRunner = Mock(CommandRunner) File keychainDestinationFile @@ -33,7 +34,9 @@ class KeychainCreateTaskSpecification extends Specification { Security mockSecurity final static String CERTIFICATE_PASSWORD = "password" - final static String FAKE_CERT_CONTENT = "Mocked certificate content" + final static String FAKE_CERT_CONTENT = "Bag Attributes\n" + + " localKeyID: FE 93 19 AC CC D7 C1 AC 82 97 02 C2 35 97 B6 CE 37 33 CB 4F\n" + + " friendlyName: iPhone Distribution: Test Company Name (12345ABCDE)" def setup() { project = ProjectBuilder.builder().build() @@ -42,8 +45,9 @@ class KeychainCreateTaskSpecification extends Specification { mockSecurity = Mock(Security) - keychainCreateTask = project.tasks.findByName('keychainCreate') as KeychainCreateTask - keychainCreateTask.security.set(new Security(commandRunner)) + subject = project.tasks.findByName('keychainCreate') as KeychainCreateTask + subject.security.set(new Security(commandRunner)) + subject.commandRunnerProperty.set(commandRunner) xcodeBuildPluginExtension = project.extensions.getByType(XcodeBuildPluginExtension) folder = xcodeBuildPluginExtension.signing @@ -64,8 +68,10 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificatePassword = CERTIFICATE_PASSWORD project.xcodebuild.signing.timeout = null - keychainCreateTask.security.set(mockSecurity) + subject.security.set(mockSecurity) mockSecurity.getKeychainList() >> [] + + commandRunner.runWithResult(_) >> FAKE_CERT_CONTENT } @Unroll @@ -75,7 +81,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.download() + subject.download() then: "The `setPartitionList` method should be call only for OS version > 10.12" 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), @@ -105,7 +111,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.download() + subject.download() then: "The `setPartitionList` method should be call only for OS version > 10.12" 1 * mockSecurity.createKeychain(xcodeBuildPluginExtension.signing.keyChainFile.asFile.get(), @@ -131,12 +137,13 @@ class KeychainCreateTaskSpecification extends Specification { @Unroll def "The keychain timeout should be called"() { given: - xcodeBuildPluginExtension.signing.certificate = certificateFile + project.xcodebuild.signing.certificate = certificateFile + if (timeout) xcodeBuildPluginExtension.signing.timeout.set(timeout) when: - keychainCreateTask.download() + subject.download() then: count * mockSecurity.setTimeout(timeout, @@ -154,7 +161,7 @@ class KeychainCreateTaskSpecification extends Specification { project.xcodebuild.signing.certificate = certificateFile when: - keychainCreateTask.download() + subject.download() then: File file = xcodeBuildPluginExtension.signing From a6030765ce5752de8001ca20b69a0ba7eeb9e0ac Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 29 May 2018 04:15:13 -0400 Subject: [PATCH 113/121] Remote the file --- errors.log | 128 ----------------------------------------------------- 1 file changed, 128 deletions(-) delete mode 100644 errors.log diff --git a/errors.log b/errors.log deleted file mode 100644 index 7ee1349d..00000000 --- a/errors.log +++ /dev/null @@ -1,128 +0,0 @@ -DRAWING THE SCREEN -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -UNREADY! -UNREADY! -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -UNREADY! -TRYING TO SPAWN -TRYING TO SPAWN -SHOULD HAVE SPAWNED -SHOULD HAVE SPAWNED -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: C -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: C -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: D -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: D -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: D -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: D -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: B -ON KEY STROKE -CURRENT INPUT:  -ON KEY STROKE -CURRENT INPUT: [ -ON KEY STROKE -CURRENT INPUT: B -YOU LOSE -GAME ENDED! -DRAWING THE SCREEN -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set -TOP is set From f85f937ed61967e93dc2ac6881ddcd8a139151e8 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Tue, 29 May 2018 05:04:34 -0400 Subject: [PATCH 114/121] Upgrade verison --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e28f48db..8889fd2a 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ allprojects { apply plugin: 'java-gradle-plugin' apply plugin: 'groovy' - def versionNumber = "0.2.8-SNAPSHOT" + def versionNumber = "0.16.0.a603076-SNAPSHOT" if (project.hasProperty("versionNumber")) { versionNumber = project.versionNumber From a82f6466f4aabb694ec160817345e45eedbacba8 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 30 May 2018 08:41:35 +0100 Subject: [PATCH 115/121] --wip-- [skip ci] --- .../org/openbakery/CommandRunner.groovy | 2 +- .../groovy/org/openbakery/XcodePlugin.groovy | 8 +- .../carthage/AbstractCarthageTaskBase.groovy | 13 +- .../carthage/CarthageBootStrapTask.groovy | 122 +++++++++++++++--- .../carthage/CarthageBootstrapRunnable.groovy | 70 ++++++++++ 5 files changed, 188 insertions(+), 27 deletions(-) create mode 100644 plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index b52aeeff..86be35ff 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) diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 60727419..40beeb79 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -692,7 +692,13 @@ class XcodePlugin implements Plugin { private void configureCarthage(Project project) { project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) - project.task(CARTHAGE_BOOTSTRAP_TASK_NAME, type: CarthageBootStrapTask, group: CARTHAGE_GROUP_NAME) +// project.task(CARTHAGE_BOOTSTRAP_TASK_NAME, type: CarthageBootStrapTask, group: CARTHAGE_GROUP_NAME) + + project.tasks.create(CARTHAGE_BOOTSTRAP_TASK_NAME, CarthageBootStrapTask.class) { + it.group = CARTHAGE_GROUP_NAME + it.commandRunnerProperty.set(commandRunner) + it.platform.set(xcodeBuildPluginExtension.type) + } } private configureCarthageDependencies(Project project) { diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy index abbb6664..2e70c2be 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -1,10 +1,14 @@ package org.openbakery.carthage +import groovy.transform.CompileStatic import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.openbakery.AbstractXcodeTask +import org.openbakery.CommandRunnerException +import org.openbakery.XcodeBuildPluginExtension import org.openbakery.xcode.Type +@CompileStatic abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { static final String ACTION_BOOTSTRAP = "bootstrap" @@ -31,7 +35,6 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @InputFile @Optional - @PathSensitive(PathSensitivity.RELATIVE) Provider getCartFile() { // Cf https://github.com/gradle/gradle/issues/2016 File file = project.rootProject.file(CARTHAGE_FILE) @@ -43,7 +46,6 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @InputFile @Optional - @PathSensitive(PathSensitivity.RELATIVE) Provider getCartResolvedFile() { // Cf https://github.com/gradle/gradle/issues/2016 File file = project.rootProject.file(CARTHAGE_FILE_RESOLVED) @@ -55,7 +57,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @Input String getCarthagePlatformName() { - switch (project.xcodebuild.type) { + switch (project.extensions.findByType(XcodeBuildPluginExtension).type.get()) { case Type.iOS: return CARTHAGE_PLATFORM_IOS case Type.tvOS: return CARTHAGE_PLATFORM_TVOS case Type.macOS: return CARTHAGE_PLATFORM_MACOS @@ -65,6 +67,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { } @OutputDirectory + @PathSensitive(PathSensitivity.NAME_ONLY) Provider getOutputDirectory() { return project.provider { project.rootProject.file("Carthage/Build/" + getCarthagePlatformName()) @@ -74,14 +77,14 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { String getCarthageCommand() { try { return commandRunner.runWithResult("which", "carthage") - } catch (CommandRunnerException) { + } catch (CommandRunnerException exception) { // ignore, because try again with full path below } try { commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) return CARTHAGE_USR_BIN_PATH - } catch (CommandRunnerException) { + } catch (CommandRunnerException exception) { // ignore, because blow an exception is thrown } throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index 7c6e8c43..5938d5d4 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -1,35 +1,117 @@ package org.openbakery.carthage import groovy.transform.CompileStatic -import org.gradle.api.tasks.TaskAction -import org.gradle.internal.logging.text.StyledTextOutputFactory -import org.openbakery.output.ConsoleOutputAppender +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.* +import org.gradle.workers.IsolationMode +import org.gradle.workers.WorkerConfiguration +import org.gradle.workers.WorkerExecutor +import org.openbakery.CommandRunner +import org.openbakery.xcode.Type +import javax.inject.Inject +import java.util.regex.Pattern + +@CacheableTask @CompileStatic -class CarthageBootStrapTask extends AbstractCarthageTaskBase { +class CarthageBootStrapTask extends DefaultTask { + + @InputFile + @PathSensitive(PathSensitivity.NAME_ONLY) + RegularFileProperty cartFile = project.layout.fileProperty() + + Property platform = project.objects.property(Type) + + @Input + Provider carthagePlatformName = platform.map { + this.typeToCarthagePlatform(it) + } as Provider + + final Property commandRunnerProperty = project.objects.property(CommandRunner) + + final WorkerExecutor workerExecutor + + static final String CARTHAGE_FILE = "Cartfile" + static final String CARTHAGE_PLATFORM_IOS = "iOS" + static final String CARTHAGE_PLATFORM_MACOS = "Mac" + static final String CARTHAGE_PLATFORM_TVOS = "tvOS" + static final String CARTHAGE_PLATFORM_WATCHOS = "watchOS" - CarthageBootStrapTask() { + static final Pattern LINE_PATTERN = ~/^(binary|github|git)\s"([^"^\/]+)\/(([^\/]+)||([^"]+)\/([^"]+).json)"."([^"]+)"$/ + + @Inject + CarthageBootStrapTask(WorkerExecutor workerExecutor) { super() + this.workerExecutor = workerExecutor + setDescription "Check out and build the Carthage project dependencies" + + cartFile.set(new File(project.rootProject.rootDir, "Cartfile.resolved")) + + onlyIf { + return cartFile.asFile.get().exists() + } + } + + @OutputDirectories + Map getOutputFiles() { + HashMap result = new HashMap<>() + cartFile.asFile + .get() + .getText() + .readLines() + .collect { return LINE_PATTERN.matcher(it) } + .findAll { it.matches() } + .collect { it.group(3) } + .each { + result.put(it, new File(project.rootProject.projectDir, + "Carthage/Build/${carthagePlatformName.get()}/${it}.framework")) + } + + return result } @TaskAction void update() { - if (hasCartFile()) { - logger.info('Boostrap Carthage for platform ' + carthagePlatformName) - def output = services.get(StyledTextOutputFactory) - .create(CarthageBootStrapTask) - - List args = [getCarthageCommand(), - ACTION_BOOTSTRAP, - ARG_PLATFORM, - carthagePlatformName, - ARG_CACHE_BUILDS] - - commandRunner.run(project.projectDir.absolutePath, - args, - getRequiredXcodeVersion() != null ? xcode.getXcodeSelectEnvValue(getRequiredXcodeVersion()) : null, - new ConsoleOutputAppender(output)) + logger.warn('Bootstrap Carthage for platform ' + carthagePlatformName) + + List names = cartFile.asFile + .get() + .getText() + .readLines() + .collect { return LINE_PATTERN.matcher(it) } + .findAll { it.matches() } + .collect { it.group(3) } + .each { createWorker(it) } + + workerExecutor.await() + } + + private void createWorker(String source) { + workerExecutor.submit(CarthageBootstrapRunnable.class) { WorkerConfiguration config -> + // Use the minimum level of isolation + config.isolationMode = IsolationMode.PROCESS + + // Constructor parameters for the unit of work implementation + config.params project.rootProject.projectDir, + source, + carthagePlatformName.get(), + commandRunnerProperty.get() + + config.displayName = "Bootstrap " + source + } + } + + private String typeToCarthagePlatform(Type type) { + switch (type) { + case Type.iOS: return CARTHAGE_PLATFORM_IOS + case Type.tvOS: return CARTHAGE_PLATFORM_TVOS + case Type.macOS: return CARTHAGE_PLATFORM_MACOS + case Type.watchOS: return CARTHAGE_PLATFORM_WATCHOS + default: return 'all' } } } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy new file mode 100644 index 00000000..932f06fc --- /dev/null +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy @@ -0,0 +1,70 @@ +package org.openbakery.carthage + +import groovy.util.logging.Slf4j +import org.openbakery.CommandRunner +import org.openbakery.CommandRunnerException +import org.openbakery.output.OutputAppender + +import javax.inject.Inject + +@Slf4j +class CarthageBootstrapRunnable implements Runnable { + + static final String ACTION_BOOTSTRAP = "bootstrap" + static final String ARG_PLATFORM = "--platform" + static final String ARG_CACHE_BUILDS = "--cache-builds" + static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" + + final File projectDir + final OutputAppender outputAppender + final String platform + final String source + final CommandRunner commandRunner + + @Inject + CarthageBootstrapRunnable(File projectDir, + String source, + String platform, + CommandRunner commandRunner) { + println "platform : " + platform + assert false + this.projectDir = projectDir + this.source = source + this.platform = platform + this.outputAppender = outputAppender + this.commandRunner = commandRunner + } + + @Override + void run() { + commandRunner.run([getCarthageCommand(), + ACTION_BOOTSTRAP, + "--color", "always", + "--project-directory", "${projectDir.absolutePath}", + ARG_CACHE_BUILDS, + ARG_PLATFORM, platform, + source], + new OutputAppender() { + @Override + void append(String output) { + log.debug(output) + } + }) + } + + String getCarthageCommand() { + try { + return commandRunner.runWithResult("which", "carthage") + } catch (CommandRunnerException exception) { + // ignore, because try again with full path below + } + + try { + commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) + return CARTHAGE_USR_BIN_PATH + } catch (CommandRunnerException exception) { + // ignore, because blow an exception is thrown + } + throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") + } +} From 4f57ba5d283252a334f2a13204d612146dcfd797 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 30 May 2018 15:25:31 +0100 Subject: [PATCH 116/121] Add the carthage bootstrap caching support --- .../groovy/org/openbakery/xcode/Xcode.groovy | 2 +- .../XcodeBuildPluginExtension.groovy | 4 + .../groovy/org/openbakery/XcodePlugin.groovy | 3 +- .../carthage/AbstractCarthageTaskBase.groovy | 2 +- .../carthage/CarthageBootStrapTask.groovy | 143 +++++++++++------- .../carthage/CarthageBootstrapRunnable.groovy | 45 ++---- 6 files changed, 114 insertions(+), 85 deletions(-) diff --git a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy index 89f80ad2..274fb4df 100644 --- a/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy +++ b/libxcode/src/main/groovy/org/openbakery/xcode/Xcode.groovy @@ -58,7 +58,7 @@ class Xcode { if (file.exists()) { result.put(ENV_DEVELOPER_DIR, file.absolutePath) } - println file.absolutePath + return result } diff --git a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy index 4823ee50..207649e8 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodeBuildPluginExtension.groovy @@ -35,6 +35,7 @@ class XcodeBuildPluginExtension { final Property bitcode = project.objects.property(Boolean) final Property version = project.objects.property(String) + final Property targetType = project.objects.property(Type) final Property scheme = project.objects.property(String) final DirectoryProperty archiveDirectory = project.layout.directoryProperty() final DirectoryProperty schemeArchiveFile = project.layout.directoryProperty() @@ -108,6 +109,8 @@ class XcodeBuildPluginExtension { this.symRoot.set(project.layout.buildDirectory.dir("sym")) this.sharedPrecompsDir.set(project.layout.buildDirectory.dir("shared")) this.derivedDataPath.set(project.layout.buildDirectory.dir("derivedData")) + + this.targetType.set(Type.iOS) } private void configureServices() { @@ -358,6 +361,7 @@ class XcodeBuildPluginExtension { void setType(String type) { this.type = Type.typeFromString(type) + this.targetType.set(this.type) } Type getType() { diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index 40beeb79..4a989c0d 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -696,8 +696,9 @@ class XcodePlugin implements Plugin { project.tasks.create(CARTHAGE_BOOTSTRAP_TASK_NAME, CarthageBootStrapTask.class) { it.group = CARTHAGE_GROUP_NAME + it.requiredXcodeVersion.set(xcodeBuildPluginExtension.version) it.commandRunnerProperty.set(commandRunner) - it.platform.set(xcodeBuildPluginExtension.type) + it.platform.set(xcodeBuildPluginExtension.targetType) } } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy index 2e70c2be..d26c96ad 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/AbstractCarthageTaskBase.groovy @@ -57,7 +57,7 @@ abstract class AbstractCarthageTaskBase extends AbstractXcodeTask { @Input String getCarthagePlatformName() { - switch (project.extensions.findByType(XcodeBuildPluginExtension).type.get()) { + switch (project.extensions.findByType(XcodeBuildPluginExtension).type) { case Type.iOS: return CARTHAGE_PLATFORM_IOS case Type.tvOS: return CARTHAGE_PLATFORM_TVOS case Type.macOS: return CARTHAGE_PLATFORM_MACOS diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index 5938d5d4..dbb86216 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -1,46 +1,54 @@ package org.openbakery.carthage import groovy.transform.CompileStatic +import org.gradle.api.Action import org.gradle.api.DefaultTask +import org.gradle.api.Transformer import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider import org.gradle.api.tasks.* -import org.gradle.workers.IsolationMode -import org.gradle.workers.WorkerConfiguration +import org.gradle.process.ExecSpec import org.gradle.workers.WorkerExecutor import org.openbakery.CommandRunner +import org.openbakery.CommandRunnerException import org.openbakery.xcode.Type +import org.openbakery.xcode.Xcode import javax.inject.Inject -import java.util.regex.Pattern @CacheableTask @CompileStatic class CarthageBootStrapTask extends DefaultTask { + @Input + @Optional + Property requiredXcodeVersion = project.objects.property(String) + + @Input + Property carthagePlatformName = project.objects.property(String) + @InputFile @PathSensitive(PathSensitivity.NAME_ONLY) RegularFileProperty cartFile = project.layout.fileProperty() - Property platform = project.objects.property(Type) - - @Input - Provider carthagePlatformName = platform.map { - this.typeToCarthagePlatform(it) - } as Provider + @OutputDirectory + Property outputDirectory = project.objects.property(File) + final Property platform = project.objects.property(Type) + final Property xcodeProperty = project.objects.property(Xcode) final Property commandRunnerProperty = project.objects.property(CommandRunner) final WorkerExecutor workerExecutor - static final String CARTHAGE_FILE = "Cartfile" + static final String CARTHAGE_FILE = "Cartfile.resolved" static final String CARTHAGE_PLATFORM_IOS = "iOS" static final String CARTHAGE_PLATFORM_MACOS = "Mac" static final String CARTHAGE_PLATFORM_TVOS = "tvOS" static final String CARTHAGE_PLATFORM_WATCHOS = "watchOS" - - static final Pattern LINE_PATTERN = ~/^(binary|github|git)\s"([^"^\/]+)\/(([^\/]+)||([^"]+)\/([^"]+).json)"."([^"]+)"$/ + static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" + static final String ACTION_BOOTSTRAP = "bootstrap" + static final String ARG_PLATFORM = "--platform" + static final String ARG_CACHE_BUILDS = "--cache-builds" @Inject CarthageBootStrapTask(WorkerExecutor workerExecutor) { @@ -49,60 +57,70 @@ class CarthageBootStrapTask extends DefaultTask { setDescription "Check out and build the Carthage project dependencies" - cartFile.set(new File(project.rootProject.rootDir, "Cartfile.resolved")) + cartFile.set(new File(project.rootProject.rootDir, CARTHAGE_FILE)) + + carthagePlatformName.set(platform.map(new Transformer() { + @Override + String transform(Type type) { + return typeToCarthagePlatform(type) + } + })) + + outputDirectory.set(carthagePlatformName.map(new Transformer() { + @Override + File transform(String platformName) { + return new File(project.rootProject.rootDir, "Carthage/Build/" + platformName) + } + })) + + xcodeProperty.set(commandRunnerProperty.map(new Transformer() { + @Override + Xcode transform(CommandRunner commandRunner) { + return new Xcode(commandRunner) + } + })) onlyIf { return cartFile.asFile.get().exists() } } - @OutputDirectories - Map getOutputFiles() { - HashMap result = new HashMap<>() - cartFile.asFile - .get() - .getText() - .readLines() - .collect { return LINE_PATTERN.matcher(it) } - .findAll { it.matches() } - .collect { it.group(3) } - .each { - result.put(it, new File(project.rootProject.projectDir, - "Carthage/Build/${carthagePlatformName.get()}/${it}.framework")) - } - - return result + public void setXcode(Xcode xcode) { + this.xcode = xcode } @TaskAction void update() { logger.warn('Bootstrap Carthage for platform ' + carthagePlatformName) - - List names = cartFile.asFile - .get() - .getText() - .readLines() - .collect { return LINE_PATTERN.matcher(it) } - .findAll { it.matches() } - .collect { it.group(3) } - .each { createWorker(it) } - - workerExecutor.await() + println "getCarthageCommand : " + getCarthageCommand() + + project.exec(new Action() { + @Override + void execute(ExecSpec execSpec) { + execSpec.args = [ACTION_BOOTSTRAP, + ARG_CACHE_BUILDS, + "--new-resolver", + "--color", "always", + ARG_PLATFORM, + carthagePlatformName.getOrNull().toString()] as List + + execSpec.environment(getEnvValues()) + execSpec.executable = getCarthageCommand() + execSpec.workingDir(project.rootProject.projectDir) + } + }) } - private void createWorker(String source) { - workerExecutor.submit(CarthageBootstrapRunnable.class) { WorkerConfiguration config -> - // Use the minimum level of isolation - config.isolationMode = IsolationMode.PROCESS - - // Constructor parameters for the unit of work implementation - config.params project.rootProject.projectDir, - source, - carthagePlatformName.get(), - commandRunnerProperty.get() - - config.displayName = "Bootstrap " + source + private final Map getEnvValues() { + final Map envValues + if (requiredXcodeVersion.present) { + envValues = xcodeProperty.get() + .getXcodeSelectEnvValue(requiredXcodeVersion.getOrNull()) + } else { + envValues = [:] } + + return envValues } private String typeToCarthagePlatform(Type type) { @@ -114,4 +132,23 @@ class CarthageBootStrapTask extends DefaultTask { default: return 'all' } } + + private String getCarthageCommand() { + try { + return commandRunnerProperty.get() + .runWithResult("which", "carthage") + } catch (CommandRunnerException exception) { + // ignore, because try again with full path below + } + + try { + commandRunnerProperty.get() + .runWithResult("ls", CARTHAGE_USR_BIN_PATH) + return CARTHAGE_USR_BIN_PATH + } catch (CommandRunnerException exception) { + // ignore, because blow an exception is thrown + } + + throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") + } } diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy index 932f06fc..5e6160a6 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy @@ -1,49 +1,52 @@ package org.openbakery.carthage -import groovy.util.logging.Slf4j +import groovy.util.logging.Log4j import org.openbakery.CommandRunner -import org.openbakery.CommandRunnerException import org.openbakery.output.OutputAppender import javax.inject.Inject -@Slf4j +@Log4j class CarthageBootstrapRunnable implements Runnable { - static final String ACTION_BOOTSTRAP = "bootstrap" - static final String ARG_PLATFORM = "--platform" - static final String ARG_CACHE_BUILDS = "--cache-builds" - static final String CARTHAGE_USR_BIN_PATH = "/usr/local/bin/carthage" + + final CommandRunner commandRunner + final String carthageCommand final File projectDir + final Map environmentValues final OutputAppender outputAppender final String platform final String source - final CommandRunner commandRunner @Inject CarthageBootstrapRunnable(File projectDir, + String carthageCommand, String source, String platform, - CommandRunner commandRunner) { - println "platform : " + platform - assert false + CommandRunner commandRunner, + Map environmentValues) { + this.carthageCommand = carthageCommand this.projectDir = projectDir this.source = source this.platform = platform this.outputAppender = outputAppender this.commandRunner = commandRunner + this.environmentValues = environmentValues } @Override void run() { - commandRunner.run([getCarthageCommand(), + log.debug("Carthage bootstrap source : " + source) + commandRunner.run([carthageCommand, ACTION_BOOTSTRAP, + ARG_CACHE_BUILDS, + "--new-resolver", "--color", "always", "--project-directory", "${projectDir.absolutePath}", - ARG_CACHE_BUILDS, ARG_PLATFORM, platform, source], + environmentValues, new OutputAppender() { @Override void append(String output) { @@ -51,20 +54,4 @@ class CarthageBootstrapRunnable implements Runnable { } }) } - - String getCarthageCommand() { - try { - return commandRunner.runWithResult("which", "carthage") - } catch (CommandRunnerException exception) { - // ignore, because try again with full path below - } - - try { - commandRunner.runWithResult("ls", CARTHAGE_USR_BIN_PATH) - return CARTHAGE_USR_BIN_PATH - } catch (CommandRunnerException exception) { - // ignore, because blow an exception is thrown - } - throw new IllegalStateException("The carthage command was not found. Make sure that Carthage is installed") - } } From be9afa92bc78cd762cee555ab2fa3537cf8bec65 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 30 May 2018 15:25:53 +0100 Subject: [PATCH 117/121] The runnable is no more needed --- .../carthage/CarthageBootstrapRunnable.groovy | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy deleted file mode 100644 index 5e6160a6..00000000 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootstrapRunnable.groovy +++ /dev/null @@ -1,57 +0,0 @@ -package org.openbakery.carthage - -import groovy.util.logging.Log4j -import org.openbakery.CommandRunner -import org.openbakery.output.OutputAppender - -import javax.inject.Inject - -@Log4j -class CarthageBootstrapRunnable implements Runnable { - - - - final CommandRunner commandRunner - final String carthageCommand - final File projectDir - final Map environmentValues - final OutputAppender outputAppender - final String platform - final String source - - @Inject - CarthageBootstrapRunnable(File projectDir, - String carthageCommand, - String source, - String platform, - CommandRunner commandRunner, - Map environmentValues) { - this.carthageCommand = carthageCommand - this.projectDir = projectDir - this.source = source - this.platform = platform - this.outputAppender = outputAppender - this.commandRunner = commandRunner - this.environmentValues = environmentValues - } - - @Override - void run() { - log.debug("Carthage bootstrap source : " + source) - commandRunner.run([carthageCommand, - ACTION_BOOTSTRAP, - ARG_CACHE_BUILDS, - "--new-resolver", - "--color", "always", - "--project-directory", "${projectDir.absolutePath}", - ARG_PLATFORM, platform, - source], - environmentValues, - new OutputAppender() { - @Override - void append(String output) { - log.debug(output) - } - }) - } -} From a35c3a153df1f30e7bc225906f49398eb4982140 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Wed, 30 May 2018 15:42:52 +0100 Subject: [PATCH 118/121] Cleanup --- 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 4a989c0d..bfa6e3c6 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -692,7 +692,6 @@ class XcodePlugin implements Plugin { private void configureCarthage(Project project) { project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) -// project.task(CARTHAGE_BOOTSTRAP_TASK_NAME, type: CarthageBootStrapTask, group: CARTHAGE_GROUP_NAME) project.tasks.create(CARTHAGE_BOOTSTRAP_TASK_NAME, CarthageBootStrapTask.class) { it.group = CARTHAGE_GROUP_NAME From 55da6f491fe87dd0a560e8614b08c0519eeddf21 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 31 May 2018 10:28:35 +0100 Subject: [PATCH 119/121] Convert the old unit to a functional one --- .../KeychainCreateTaskFunctionalTest.groovy | 8 +- ...CarthageBootStrapTaskFunctionalTest.groovy | 127 +++++++++++++++ ...ovisioningInstallTaskFunctionalTest.groovy | 6 +- .../groovy/org/openbakery/XcodePlugin.groovy | 7 +- .../carthage/CarthageBootStrapTask.groovy | 6 +- .../carthage/CarthageBootStrapTaskTest.groovy | 150 ------------------ 6 files changed, 142 insertions(+), 162 deletions(-) create mode 100644 plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy delete mode 100644 plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy diff --git a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy index c93801a1..71b02662 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/KeychainCreateTaskFunctionalTest.groovy @@ -75,7 +75,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "$certificate.absolutePath" } } """ @@ -84,6 +84,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { BuildResult result = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments(KeychainCreateTask.TASK_NAME) + .withDebug(true) .withPluginClasspath(pluginClasspath) .build() @@ -96,7 +97,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" } } @@ -107,6 +108,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { .withProjectDir(testProjectDir.root) .withArguments(KeychainCreateTask.TASK_NAME) .withPluginClasspath(pluginClasspath) + .withDebug(true) .build() then: @@ -118,7 +120,7 @@ class KeychainCreateTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - certificate = project.provisioningFile1("$certificate") + certificateURI = "${certificate.toURI().toString()}" certificatePassword = "p4ssword" } } diff --git a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy new file mode 100644 index 00000000..a753b3c4 --- /dev/null +++ b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy @@ -0,0 +1,127 @@ +package org.openbakery.carthage + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +class CarthageBootStrapTaskFunctionalTest extends Specification { + @Rule + final TemporaryFolder testProjectDir = new TemporaryFolder() + + List pluginClasspath + File buildFile + GradleRunner gradleRunner + File carthageFolder + + void setup() { + buildFile = testProjectDir.newFile('build.gradle') + + buildFile << """ + plugins { + id 'org.openbakery.xcode-plugin' + } + """ + + def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { + throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") + } + + pluginClasspath = pluginClasspathResource.readLines().collect { new File(it) } + + gradleRunner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments(CarthageBootStrapTask.NAME) + .withPluginClasspath(pluginClasspath) + + carthageFolder = new File(testProjectDir.root, "Carthage") + } + + def "The task list should contain the task"() { + when: + BuildResult result = gradleRunner.build() + + then: + result.output.contains(CarthageBootStrapTask.NAME) + } + + def "The task should be skipped if no cartfile is present"() { + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SKIPPED + } + + def "The task should be executed with success if a `cartfile.resolved` file is present"() { + setup: + testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + } + + def "The task should resolve the defined carthage dependencies"() { + setup: + File carthageFile = testProjectDir.newFile("Cartfile") + carthageFile << """ + github "ashleymills/Reachability.swift" + """ + + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + carthageResolvedFile << """ + github "ashleymills/Reachability.swift" "v4.1.0" + """ + + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The resolved framework should be existing only for iOS (default target)" + carthageFolder.exists() + new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + !new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + } + + def "The task should resolve the defined carthage dependencies depending of the configured target"() { + setup: + File carthageFile = testProjectDir.newFile("Cartfile") + carthageFile << """ + github "ashleymills/Reachability.swift" + """ + + File carthageResolvedFile = testProjectDir.newFile(CarthageBootStrapTask.CARTHAGE_FILE) + carthageResolvedFile << """ + github "ashleymills/Reachability.swift" "v4.1.0" + """ + + buildFile << """ + xcodebuild { + type = "tvOS" + } + """ + + when: + BuildResult result = gradleRunner.build() + + then: + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.SUCCESS + + and: "The resolved framework should be existing only for iOS (default target)" + carthageFolder.exists() + !new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + } +} diff --git a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy index d20157ff..16dce6f6 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/signing/ProvisioningInstallTaskFunctionalTest.groovy @@ -30,7 +30,9 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { provisioningFile1 = findResource("test1.mobileprovision") assert provisioningFile1.exists() - def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") + def pluginClasspathResource = getClass().classLoader + .findResource("plugin-classpath.txt") + if (pluginClasspathResource == null) { throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") } @@ -70,7 +72,7 @@ class ProvisioningInstallTaskFunctionalTest extends Specification { buildFile << """ xcodebuild { signing { - mobileProvisionURI = [] + mobileProvisionList = [] } } """ diff --git a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy index bfa6e3c6..ce142110 100644 --- a/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy +++ b/plugin/src/main/groovy/org/openbakery/XcodePlugin.groovy @@ -116,7 +116,6 @@ class XcodePlugin implements Plugin { public static final String OCLINT_TASK_NAME = 'oclint' public static final String OCLINT_REPORT_TASK_NAME = 'oclintReport' public static final String CPD_TASK_NAME = 'cpd' - public static final String CARTHAGE_BOOTSTRAP_TASK_NAME = 'carthageBootstrap' public static final String CARTHAGE_UPDATE_TASK_NAME = 'carthageUpdate' public static final String CARTHAGE_CLEAN_TASK_NAME = 'carthageClean' @@ -522,7 +521,7 @@ class XcodePlugin implements Plugin { } private void configureSimulatorTasks(Project project) { - project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask, group: SIMULATORS_LIST_TASK_NAME) + project.task(SIMULATORS_LIST_TASK_NAME, type: SimulatorsListTask.class, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CREATE_TASK_NAME, type: SimulatorsCreateTask, group: SIMULATORS_LIST_TASK_NAME) project.task(SIMULATORS_CLEAN_TASK_NAME, type: SimulatorsCleanTask, group: SIMULATORS_LIST_TASK_NAME) @@ -693,7 +692,7 @@ class XcodePlugin implements Plugin { project.task(CARTHAGE_CLEAN_TASK_NAME, type: CarthageCleanTask, group: CARTHAGE_GROUP_NAME) project.task(CARTHAGE_UPDATE_TASK_NAME, type: CarthageUpdateTask, group: CARTHAGE_GROUP_NAME) - project.tasks.create(CARTHAGE_BOOTSTRAP_TASK_NAME, CarthageBootStrapTask.class) { + project.tasks.create(CarthageBootStrapTask.NAME, CarthageBootStrapTask.class) { it.group = CARTHAGE_GROUP_NAME it.requiredXcodeVersion.set(xcodeBuildPluginExtension.version) it.commandRunnerProperty.set(commandRunner) @@ -702,7 +701,7 @@ class XcodePlugin implements Plugin { } private configureCarthageDependencies(Project project) { - CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CARTHAGE_BOOTSTRAP_TASK_NAME) + CarthageBootStrapTask bootStrapTask = project.getTasks().getByName(CarthageBootStrapTask.NAME) as CarthageBootStrapTask addDependencyToBuild(project, bootStrapTask) project.getTasks() diff --git a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy index dbb86216..94df3517 100644 --- a/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy +++ b/plugin/src/main/groovy/org/openbakery/carthage/CarthageBootStrapTask.groovy @@ -34,6 +34,8 @@ class CarthageBootStrapTask extends DefaultTask { @OutputDirectory Property outputDirectory = project.objects.property(File) + public static final String NAME = "carthageBootstrap" + final Property platform = project.objects.property(Type) final Property xcodeProperty = project.objects.property(Xcode) final Property commandRunnerProperty = project.objects.property(CommandRunner) @@ -85,15 +87,13 @@ class CarthageBootStrapTask extends DefaultTask { } } - public void setXcode(Xcode xcode) { + void setXcode(Xcode xcode) { this.xcode = xcode } @TaskAction void update() { logger.warn('Bootstrap Carthage for platform ' + carthagePlatformName) - println "getCarthageCommand : " + getCarthageCommand() - project.exec(new Action() { @Override void execute(ExecSpec execSpec) { diff --git a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy b/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy deleted file mode 100644 index 8f45eeb5..00000000 --- a/plugin/src/test/groovy/org/openbakery/carthage/CarthageBootStrapTaskTest.groovy +++ /dev/null @@ -1,150 +0,0 @@ -package org.openbakery.carthage - -import org.gradle.api.Project -import org.gradle.api.provider.Provider -import org.gradle.testfixtures.ProjectBuilder -import org.junit.Rule -import org.junit.rules.ExpectedException -import org.openbakery.CommandRunner -import org.openbakery.output.ConsoleOutputAppender -import org.openbakery.xcode.Xcode -import spock.lang.Specification -import spock.lang.Unroll - -import static org.openbakery.carthage.AbstractCarthageTaskBase.* -import static org.openbakery.xcode.Type.* - -class CarthageBootStrapTaskTest extends Specification { - - CarthageBootStrapTask subject - CommandRunner commandRunner = Mock(CommandRunner) - Xcode mockXcode = Mock(Xcode) - File projectDir - File cartFile - Project project - - @Rule - public ExpectedException exception = ExpectedException.none() - - void setup() { - projectDir = File.createTempDir() - - cartFile = new File(projectDir, "Cartfile") - cartFile << 'github "Alamofire/Alamofire"' - - project = ProjectBuilder.builder() - .withProjectDir(projectDir) - .build() - - project.buildDir = new File(projectDir, 'build').absoluteFile - project.apply plugin: org.openbakery.XcodePlugin - - subject = project.getTasks().getByPath('carthageBootstrap') - assert subject != null - - subject.commandRunner = commandRunner - } - - def "The carthage bootstrap task should be present"() { - expect: - subject instanceof CarthageBootStrapTask - } - - @Unroll - def "When bootstrap is executed should only update the platform: #platform"() { - given: - commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" - project.xcodebuild.type = platform - - when: - subject.update() - - then: - 1 * commandRunner.run(_, - [CARTHAGE_USR_BIN_PATH, - ACTION_BOOTSTRAP, - ARG_PLATFORM, - carthagePlatform, - ARG_CACHE_BUILDS] - , _ - , _) >> { - args -> args[3] instanceof ConsoleOutputAppender - } - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The task should not be executed if the 'Cartfile` file is missing"() { - given: - commandRunner.runWithResult("which", "carthage") >> "/usr/local/bin/carthage" - project.xcodebuild.type = platform - - when: - cartFile.delete() - subject.update() - - then: - 0 * commandRunner.run(_, - getCommandRunnerArgsForPlatform(carthagePlatform), - _, - _) >> { - args -> args[3] instanceof ConsoleOutputAppender - } - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The subject output directory should be platform dependant"() { - when: - subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() - project.xcodebuild.type = platform - - then: - Provider outputDirectory = subject.outputDirectory - outputDirectory.isPresent() - outputDirectory.get().name == carthagePlatform - - where: - platform | carthagePlatform - tvOS | CARTHAGE_PLATFORM_TVOS - macOS | CARTHAGE_PLATFORM_MACOS - watchOS | CARTHAGE_PLATFORM_WATCHOS - iOS | CARTHAGE_PLATFORM_IOS - } - - def "The xcode selection should be applied if a xcode version is defined"() { - when: - subject.xcode.getXcodeSelectEnvValue(_) >> new HashMap() - project.xcodebuild.type = iOS - project.xcodebuild.version = version - - subject.xcode = mockXcode - subject.xcode.setVersionFromString(_) >> _ - subject.update() - - then: - 1 * mockXcode.getXcodeSelectEnvValue(version) - - where: - version | _ - "7.1.1" | _ - } - - private List getCommandRunnerArgsForPlatform(String carthagePlatform) { - return [CARTHAGE_USR_BIN_PATH, - ACTION_UPDATE, - ARG_PLATFORM, - carthagePlatform, - ARG_CACHE_BUILDS] - } -} From c372b0ea52d22e1c04e506d0190c2aed2fcba71d Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 31 May 2018 10:48:39 +0100 Subject: [PATCH 120/121] Add a FROM_CACHE functional test --- .../CarthageBootStrapTaskFunctionalTest.groovy | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy index a753b3c4..ec6a21fc 100644 --- a/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy +++ b/plugin/src/functionalTest/groovy/org/openbakery/carthage/CarthageBootStrapTaskFunctionalTest.groovy @@ -82,7 +82,8 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { """ when: - BuildResult result = gradleRunner.build() + BuildResult result = gradleRunner + .build() then: result.task(":" + CarthageBootStrapTask.NAME) @@ -92,6 +93,18 @@ class CarthageBootStrapTaskFunctionalTest extends Specification { carthageFolder.exists() new File(carthageFolder, "Build/iOS/Reachability.framework").exists() !new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() + + when: "Force reset and build with cache enabled" + assert carthageFolder.deleteDir() + result = gradleRunner.withArguments('--build-cache', CarthageBootStrapTask.NAME) + .build() + + then: "Should resolve the carthage dependencies from cache" + result.task(":" + CarthageBootStrapTask.NAME) + .outcome == TaskOutcome.FROM_CACHE + + new File(carthageFolder, "Build/iOS/Reachability.framework").exists() + !new File(carthageFolder, "Build/tvOS/Reachability.framework").exists() } def "The task should resolve the defined carthage dependencies depending of the configured target"() { From ac6025a9a2b84b039b7f8fa63530afef57253de9 Mon Sep 17 00:00:00 2001 From: Johann Martinache Date: Thu, 31 May 2018 10:49:14 +0100 Subject: [PATCH 121/121] No more necessary --- libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy b/libxcode/src/main/groovy/org/openbakery/CommandRunner.groovy index 86be35ff..b52aeeff 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 implements Serializable{ +class CommandRunner { private static Logger logger = LoggerFactory.getLogger(CommandRunner.class)