Skip to content

Commit

Permalink
Improve multiple provisioning profiles support (#162)
Browse files Browse the repository at this point in the history
Description
===========

This patch adds a new fastlane task type `SighRenewBatch` which
allows to set a map of `bundleId` -> `profileName`.
This allows to set the map pulled from the `exportOption.plist` into
the `importProvisioningProfiles` task.

I'm not 100% happy with the implementation but one could revisit this
with another patch to rework the inner workings.

At the moment the new task type simply extends `SighRenew` and
adds a `profiles` property which gets looped over. The task action
of `SighRenew` is called multiple times. This has the desired effect
but can cause issues with input caching etc. I'm fine with this from
a first version prespective

Changes
=======

* ![IMPROVE] multiple provisioning profiles support
  • Loading branch information
Larusso authored May 25, 2022
1 parent 3e757bf commit ababeb3
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 63 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ repositories {
dependencies {
implementation "net.wooga.gradle:dotnet-sonarqube:[0.4,0.5["
implementation "net.wooga.gradle:unity:[3,4["
implementation 'com.wooga.gradle:gradle-commons:[1,2['
implementation 'com.wooga.gradle:gradle-commons:[1.2.2,2['
implementation 'com.wooga.gradle:gradle-commons-test:[1.1.1,2['
implementation "org.gradle:gradle-tooling-api:+"
api 'net.wooga.gradle:secrets:1.0.0-rc.6'
api 'software.amazon.awssdk:secretsmanager:[2.16,3['
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package wooga.gradle.fastlane

import com.wooga.gradle.test.PropertyLocation
import com.wooga.gradle.test.PropertyQueryTaskWriter
import spock.lang.Requires
import spock.lang.Unroll
import wooga.gradle.fastlane.tasks.PilotUpload
import wooga.gradle.fastlane.tasks.SighRenew
Expand Down Expand Up @@ -65,37 +64,48 @@ class FastlanePluginIntegrationSpec extends FastlaneIntegrationSpec {
query.matches(result, testValue)

where:
property | method | rawValue | expectedValue | type | location | additionalInfo
"username" | _ | "someUser1" | _ | _ | PropertyLocation.environment | ""
"username" | _ | "someUser2" | _ | _ | PropertyLocation.property | ""
"username" | _ | "someUser3" | _ | "String" | PropertyLocation.script | ""
"username" | _ | "someUser4" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | "username.set" | "someUser5" | _ | "String" | PropertyLocation.script | ""
"username" | "username.set" | "someUser6" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | "username" | "someUser7" | _ | "String" | PropertyLocation.script | ""
"username" | "username" | "someUser8" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | _ | _ | null | _ | PropertyLocation.none | ""


"password" | _ | "somePassword1" | _ | _ | PropertyLocation.environment | ""
"password" | _ | "somePassword2" | _ | _ | PropertyLocation.property | ""
"password" | _ | "somePassword3" | _ | "String" | PropertyLocation.script | ""
"password" | _ | "somePassword4" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | "password.set" | "somePassword5" | _ | "String" | PropertyLocation.script | ""
"password" | "password.set" | "somePassword6" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | "password" | "somePassword7" | _ | "String" | PropertyLocation.script | ""
"password" | "password" | "somePassword8" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | _ | _ | null | _ | PropertyLocation.none | ""

"apiKeyPath" | _ | osPath("/path/to/key1.json") | _ | _ | PropertyLocation.environment | ""
"apiKeyPath" | _ | osPath("/path/to/key2.json") | _ | _ | PropertyLocation.property | ""
"apiKeyPath" | _ | osPath("/path/to/key3.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | _ | osPath("/path/to/key4.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath.set" | osPath("/path/to/key5.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath.set" | osPath("/path/to/key6.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath" | osPath("/path/to/key7.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath" | osPath("/path/to/key8.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | _ | _ | null | _ | PropertyLocation.none | ""
property | method | rawValue | expectedValue | type | location | additionalInfo
"username" | _ | "someUser1" | _ | _ | PropertyLocation.environment | ""
"username" | _ | "someUser2" | _ | _ | PropertyLocation.property | ""
"username" | _ | "someUser3" | _ | "String" | PropertyLocation.script | ""
"username" | _ | "someUser4" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | "username.set" | "someUser5" | _ | "String" | PropertyLocation.script | ""
"username" | "username.set" | "someUser6" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | "username" | "someUser7" | _ | "String" | PropertyLocation.script | ""
"username" | "username" | "someUser8" | _ | "Provider<String>" | PropertyLocation.script | ""
"username" | _ | _ | null | _ | PropertyLocation.none | ""


"password" | _ | "somePassword1" | _ | _ | PropertyLocation.environment | ""
"password" | _ | "somePassword2" | _ | _ | PropertyLocation.property | ""
"password" | _ | "somePassword3" | _ | "String" | PropertyLocation.script | ""
"password" | _ | "somePassword4" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | "password.set" | "somePassword5" | _ | "String" | PropertyLocation.script | ""
"password" | "password.set" | "somePassword6" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | "password" | "somePassword7" | _ | "String" | PropertyLocation.script | ""
"password" | "password" | "somePassword8" | _ | "Provider<String>" | PropertyLocation.script | ""
"password" | _ | _ | null | _ | PropertyLocation.none | ""

"apiKeyPath" | _ | osPath("/path/to/key1.json") | _ | _ | PropertyLocation.environment | ""
"apiKeyPath" | _ | osPath("/path/to/key2.json") | _ | _ | PropertyLocation.property | ""
"apiKeyPath" | _ | osPath("/path/to/key3.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | _ | osPath("/path/to/key4.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath.set" | osPath("/path/to/key5.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath.set" | osPath("/path/to/key6.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath" | osPath("/path/to/key7.json") | _ | "File" | PropertyLocation.script | ""
"apiKeyPath" | "apiKeyPath" | osPath("/path/to/key8.json") | _ | "Provider<RegularFile>" | PropertyLocation.script | ""
"apiKeyPath" | _ | _ | null | _ | PropertyLocation.none | ""

"skip2faUpgrade" | _ | true | _ | _ | PropertyLocation.environment | ""
"skip2faUpgrade" | _ | true | _ | _ | PropertyLocation.property | ""
"skip2faUpgrade" | _ | true | _ | "Boolean" | PropertyLocation.script | ""
"skip2faUpgrade" | _ | true | _ | "Provider<Boolean>" | PropertyLocation.script | ""
"skip2faUpgrade" | "skip2faUpgrade.set" | true | _ | "Boolean" | PropertyLocation.script | ""
"skip2faUpgrade" | "skip2faUpgrade.set" | true | _ | "Provider<Boolean>" | PropertyLocation.script | ""
"skip2faUpgrade" | "skip2faUpgrade" | true | _ | "Boolean" | PropertyLocation.script | ""
"skip2faUpgrade" | "skip2faUpgrade" | true | _ | "Provider<Boolean>" | PropertyLocation.script | ""
"skip2faUpgrade" | _ | _ | false | _ | PropertyLocation.none | ""

extensionName = "fastlane"
value = (type != _) ? wrapValueBasedOnType(rawValue, type) : rawValue
providedValue = (location == PropertyLocation.script) ? type : value
Expand Down Expand Up @@ -128,15 +138,18 @@ class FastlanePluginIntegrationSpec extends FastlaneIntegrationSpec {
query.matches(result, testValue)

where:
property | extensionProperty | tasktype | rawValue | expectedValue | type | useProviderApi
"username" | "username" | SighRenew | "userName1" | _ | "String" | true
"username" | "username" | PilotUpload | "userName2" | _ | "String" | true
property | extensionProperty | tasktype | rawValue | expectedValue | type | useProviderApi
"username" | "username" | SighRenew | "userName1" | _ | "String" | true
"username" | "username" | PilotUpload | "userName2" | _ | "String" | true

"password" | "password" | SighRenew | "password1" | _ | "String" | true
"password" | "password" | PilotUpload | "password2" | _ | "String" | true

"password" | "password" | SighRenew | "password1" | _ | "String" | true
"password" | "password" | PilotUpload | "password2" | _ | "String" | true
"apiKeyPath" | "apiKeyPath" | SighRenew | osPath("/path/to/key1.json") | _ | "File" | true
"apiKeyPath" | "apiKeyPath" | PilotUpload | osPath("/path/to/key2.json") | _ | "File" | true

"apiKeyPath" | "apiKeyPath" | SighRenew | osPath("/path/to/key1.json") | _ | "File" | true
"apiKeyPath" | "apiKeyPath" | PilotUpload | osPath("/path/to/key2.json") | _ | "File" | true
"skip2faUpgrade" | "skip2faUpgrade" | SighRenew | true | _ | "Boolean" | true
"skip2faUpgrade" | "skip2faUpgrade" | PilotUpload | true | _ | "Boolean" | true

extensionName = "fastlane"
taskName = "fastlaneTask"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ class IntegrationSpec extends com.wooga.gradle.test.IntegrationSpec {
this.gradleVersion = gradleVersion
fork = true
}
environmentVariables.clear("FASTLANE_USERNAME", "FASTLANE_PASSWORD")
environmentVariables.clear("FASTLANE_USERNAME", "FASTLANE_PASSWORD", "FASTLANE_API_KEY_PATH", "SPACESHIP_SKIP_2FA_UPGRADE", "FASTLANE_SKIP_2FA_UPGRADE")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package wooga.gradle.fastlane.tasks

import spock.lang.Requires
import spock.lang.Unroll

@Requires({ os.macOs })
class SighRenewBatchIntegrationSpec extends SighRenewIntegrationSpec {
String testTaskName = "sighRenewBatch"
Class taskType = SighRenewBatch

String workingFastlaneTaskConfig = """
task("${testTaskName}", type: ${taskType.name}) {
appIdentifier = 'test'
teamId = "fakeTeamId"
destinationDir = file('build')
profiles = ["foo.bar.baz":"fooBar"]
}
""".stripIndent()

def "imports multiple profiles"() {
given: "set multiple profiles"
buildFile << """
${testTaskName} {
profiles = ${wrapValueBasedOnType(profiles, "Map<String,String>")}
}
"""

when:
def result = runTasksSuccessfully(testTaskName)

then:
profiles.each { bundleId, profileName ->
result.standardOutput.contains("import provisioning profile '${profileName}' for bundleIdentifier '${bundleId}' to file '${profileName}.mobileprovision'")
}

where:
profileNames = ["profile1", "profile2", "profile3"]
bundleIds = ["net.test.app1", "net.test.app2", "net.test.app3"]
profiles = [bundleIds, profileNames].transpose().collectEntries()
}

@Unroll
def "imports configured profileName/appIdentifier when set"() {
given: "set multiple profiles"
buildFile << """
${testTaskName} {
profiles = ${wrapValueBasedOnType(profiles, "Map<String,String>")}
appIdentifier = ${appIdentifier ? wrapValueBasedOnType(appIdentifier, String) : null}
provisioningName = ${provisioningName ? wrapValueBasedOnType(provisioningName, String) : null}
}
"""

when:
def result = runTasksSuccessfully(testTaskName)

then:
result.standardOutput.contains("import ${expectedProfiles.size()} profiles")
profiles.each { bundleId, profileName ->
result.standardOutput.contains("import provisioning profile '${profileName}' for bundleIdentifier '${bundleId}' to file '${profileName}.mobileprovision'")
}

where:
provisioningName | appIdentifier | profiles || expectedProfiles
null | null | ["foo.bar.baz": "FooBar"] || profiles
"FooBar" | "foo.bar.baz" | ["foo.bar.baz": "FooBar"] || profiles
"FooBar" | null | ["foo.bar.baz": "FooBar"] || profiles
null | "foo.bar.baz" | ["foo.bar.baz": "FooBar"] || profiles
"FooBar2" | "foo.bar.baz" | ["foo.bar.baz": "FooBar"] || ["foo.bar.baz": "FooBar", (appIdentifier): (provisioningName)]
"BazBar" | "baz.foo.bar" | ["foo.bar.baz": "FooBar"] || ["foo.bar.baz": "FooBar", (appIdentifier): (provisioningName)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ class SighRenewIntegrationSpec extends AbstractFastlaneTaskIntegrationSpec {
buildFile << """
task("readValue") {
doLast {
println("arguments: " + ${testTaskName}.arguments.get().join(" "))
println("arguments: " + ${getTestTaskName()}.arguments.get().join(" "))
}
}
""".stripIndent()

and: "a set property"
if (method != _) {
buildFile << """
${testTaskName}.${method}($value)
${getTestTaskName()}.${method}($value)
""".stripIndent()
}

Expand Down Expand Up @@ -99,15 +99,15 @@ class SighRenewIntegrationSpec extends AbstractFastlaneTaskIntegrationSpec {
buildFile << """
task("readValue") {
doLast {
println("arguments: " + ${testTaskName}.environment.get().collect {k,v -> k + '=' + v}.join("\\n"))
println("arguments: " + ${getTestTaskName()}.environment.get().collect {k,v -> k + '=' + v}.join("\\n"))
}
}
""".stripIndent()

and: "a set property"
if (method != _) {
buildFile << """
${testTaskName}.${method}($value)
${getTestTaskName()}.${method}($value)
""".stripIndent()
}

Expand All @@ -118,8 +118,9 @@ class SighRenewIntegrationSpec extends AbstractFastlaneTaskIntegrationSpec {
outputContains(result, expectedEnvironmentPair)

where:
property | method | rawValue | type || expectedEnvironmentPair
"password" | "password.set" | "secretValue" | "String" || "FASTLANE_PASSWORD=secretValue"
property | method | rawValue | type || expectedEnvironmentPair
"password" | "password.set" | "secretValue" | "String" || "FASTLANE_PASSWORD=secretValue"
"skip2faUpgrade" | "skip2faUpgrade.set" | true | "BOLEAN" || "SPACESHIP_SKIP_2FA_UPGRADE=1"
value = wrapValueBasedOnType(rawValue, type)
valueMessage = (rawValue != _) ? "with value ${value}" : "without value"
}
Expand All @@ -130,14 +131,14 @@ class SighRenewIntegrationSpec extends AbstractFastlaneTaskIntegrationSpec {
buildFile << """
task("readValue") {
doLast {
println("property: " + ${testTaskName}.${property}.get())
println("property: " + ${getTestTaskName()}.${property}.get())
}
}
""".stripIndent()

and: "a set property"
buildFile << """
${testTaskName}.${method}($value)
${getTestTaskName()}.${method}($value)
""".stripIndent()

// TODO: Refactor
Expand Down Expand Up @@ -255,12 +256,12 @@ class SighRenewIntegrationSpec extends AbstractFastlaneTaskIntegrationSpec {
@Issue("https://github.com/wooga/atlas-build-unity/issues/38")
def "task is never up-to-date"() {
given: "call import tasks once"
def r = runTasks(testTaskName)
def r = runTasks(getTestTaskName())

when: "no parameter changes"
def result = runTasksSuccessfully(testTaskName)
def result = runTasksSuccessfully(getTestTaskName())

then:
!result.wasUpToDate(testTaskName)
!result.wasUpToDate(getTestTaskName())
}
}
Loading

0 comments on commit ababeb3

Please sign in to comment.