Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Commit

Permalink
add binary property and artifact() method to extension (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joaquimmnetto authored Jun 18, 2024
1 parent 116fbf2 commit a8fe5b4
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 32 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ cveHandler {
dependencies {
implementation 'org.apache.httpcomponents:httpclient:4.5.13'
implementation 'org.apache.httpcomponents:httpmime:4.5.13'
implementation 'com.wooga.gradle:gradle-commons:[1,2)'
implementation 'com.wooga.gradle:gradle-commons:[2,3)'
testImplementation 'com.wooga.gradle:gradle-commons-test:[2,3)'
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,13 @@ class AppCenterPluginIntegrationSpec extends IntegrationSpec {

@Unroll
def "can set property :#property with :#method and type '#type'"() {
given: "a task to print appCenter properties"
given: "the test value with replace placeholders"
def value = rawValue
if (value instanceof String) {
value = value.replaceAll("#projectDir#", escapedPath(projectDir.path))
}

and: "a task to print appCenter properties"
buildFile << """
task(custom) {
doLast {
Expand All @@ -156,18 +162,20 @@ class AppCenterPluginIntegrationSpec extends IntegrationSpec {
"""

and: "some configured property"
buildFile << "appCenter.${method}(${value})"
buildFile << "appCenter.${method}(${wrapValueBasedOnType(value, type)})"

and: "the test value with replace placeholders"
if (value instanceof String) {
value = value.replaceAll("#projectDir#", escapedPath(projectDir.path))
}

when: ""

when:
def result = runTasksSuccessfully("custom")
and:

if(type.contains("File")) {
value = new File(value).path
}

then:
result.standardOutput.contains("appCenter.${property}: ${rawValue}")
result.standardOutput.contains("appCenter.${property}: ${value}")

where:
property | method | rawValue | type
Expand All @@ -176,6 +184,18 @@ class AppCenterPluginIntegrationSpec extends IntegrationSpec {
"apiToken" | "apiToken.set" | "testToken3" | "Provider<String>"
"apiToken" | "setApiToken" | "testToken4" | "String"
"apiToken" | "setApiToken" | "testToken5" | "Provider<String>"

"binary" | "binary.set" | "#projectDir#/bin2" | "RegularFile"
"binary" | "binary.set" | "#projectDir#/bin3" | "Provider<RegularFile>"
"binary" | "setBinary" | "#projectDir#/bin4" | "File"
"binary" | "setBinary" | "#projectDir#/bin4" | "RegularFile"
"binary" | "setBinary" | "#projectDir#/bin5" | "Provider<RegularFile>"

"releaseNotes" | "releaseNotes.set" | "notes2" | "String"
"releaseNotes" | "releaseNotes.set" | "notes3" | "Provider<String>"
"releaseNotes" | "setReleaseNotes" | "notes4" | "String"
"releaseNotes" | "setReleaseNotes" | "notes5" | "Provider<String>"

"owner" | "owner" | "owner1" | "String"
"owner" | "owner.set" | "owner2" | "String"
"owner" | "owner.set" | "owner3" | "Provider<String>"
Expand All @@ -186,7 +206,6 @@ class AppCenterPluginIntegrationSpec extends IntegrationSpec {
"applicationIdentifier" | "applicationIdentifier.set" | "applicationIdentifier3" | "Provider<String>"
"applicationIdentifier" | "setApplicationIdentifier" | "applicationIdentifier4" | "String"
"applicationIdentifier" | "setApplicationIdentifier" | "applicationIdentifier5" | "Provider<String>"
value = wrapValueBasedOnType(rawValue, type)
}


Expand Down Expand Up @@ -257,4 +276,43 @@ class AppCenterPluginIntegrationSpec extends IntegrationSpec {
message = (dependsOnTask) ? "depends" : "depends not"
}

def "uploads artifact set with appCenter.artifact() method"() {
given: "a project with property set"
def artifactFile = new File(projectDir, "artifacts/artifact.ipa")
buildFile << """
def artifactTask = tasks.register("$artifactTaskName", Copy) {
from ${wrapValueBasedOnType(getClass().classLoader.getResource("test.ipa").path, "File")}
into ${wrapValueBasedOnType(artifactFile.parentFile.absolutePath, "File")}
rename ".*", ${wrapValueBasedOnType(artifactFile.name, "String")}
}
configurations.create("test")
artifacts.add("test", artifactTask.map {
it.outputs.files.find {
it.absolutePath == ${wrapValueBasedOnType(artifactFile.absolutePath, "File")}
}
}) { it.type = "myartifact" }
def artifactObj = configurations.test.artifacts.matching { it.type == "myartifact" }.first()
appCenter {
owner = "$owner"
apiToken = "$apiToken"
applicationIdentifier = "$applicationIdentifier"
publishEnabled = true
artifact(artifactObj)
}
"""

and: "a dummy ipa binary to upload"
def testFile = getClass().getClassLoader().getResource("test.ipa").path
buildFile << """
publishAppCenter.binary = file("$testFile")
""".stripIndent()

expect:
def result = runTasksSuccessfully("publishAppCenter")
result.wasExecuted(artifactTaskName)

where:
artifactTaskName = "artifactTask"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package wooga.gradle.appcenter

import com.wooga.gradle.test.PropertyUtils
import groovy.json.StringEscapeUtils
import nebula.test.functional.ExecutionResult

Expand Down Expand Up @@ -101,7 +102,7 @@ class IntegrationSpec extends nebula.test.IntegrationSpec {
value = "${rawValue}L"
break
default:
value = rawValue
value = PropertyUtils.wrapValue(rawValue, type)
}
value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import org.apache.http.impl.client.HttpClientBuilder
import spock.lang.Unroll
import wooga.gradle.appcenter.AppCenterPlugin
import wooga.gradle.appcenter.IntegrationSpec
import wooga.gradle.appcenter.error.RetryableException

import java.util.function.Supplier

class AppCenterUploadTaskIntegrationSpec extends IntegrationSpec {
static String apiToken = System.env["ATLAS_APP_CENTER_INTEGRATION_API_TOKEN"]
Expand Down Expand Up @@ -478,25 +481,27 @@ class AppCenterUploadTaskIntegrationSpec extends IntegrationSpec {
}

Map<String, String> ensureDistributionGroup(String name) {
HttpClient client = HttpClientBuilder.create().build()
HttpPost request = new HttpPost("https://api.appcenter.ms/v0.1/apps/${owner}/${applicationIdentifierIos}/distribution_groups")
retry(5, 500) {
HttpClient client = HttpClientBuilder.create().build()
HttpPost request = new HttpPost("https://api.appcenter.ms/v0.1/apps/${owner}/${applicationIdentifierIos}/distribution_groups")

request.setHeader("Accept", 'application/json')
request.setHeader("X-API-Token", apiToken)
request.setHeader("Accept", 'application/json')
request.setHeader("X-API-Token", apiToken)

def body = ["name": name]
request.setEntity(new StringEntity(JsonOutput.toJson(body), ContentType.APPLICATION_JSON))
def body = ["name": name]
request.setEntity(new StringEntity(JsonOutput.toJson(body), ContentType.APPLICATION_JSON))

HttpResponse response = client.execute(request)
HttpResponse response = client.execute(request)

if (response.statusLine.statusCode != 201 && response.statusLine.statusCode != 409) {
throw new Exception("Failed to create distribution group")
} else if (response.statusLine.statusCode == 409) {
return loadDistributionGroup(name)
}
if (response.statusLine.statusCode != 201 && response.statusLine.statusCode != 409) {
throw new RetryableException("Failed to create distribution group")
} else if (response.statusLine.statusCode == 409) {
return loadDistributionGroup(name)
}

def jsonSlurper = new JsonSlurper()
jsonSlurper.parseText(response.entity.content.text) as Map
def jsonSlurper = new JsonSlurper()
return jsonSlurper.parseText(response.entity.content.text) as Map
}
}

Map<String, String> loadDistributionGroup(String name) {
Expand Down Expand Up @@ -535,4 +540,18 @@ class AppCenterUploadTaskIntegrationSpec extends IntegrationSpec {
def jsonSlurper = new JsonSlurper()
jsonSlurper.parseText(response.entity.content.text) as Map
}

<T> T retry(int maxRetries, long waitMs, Supplier<T> operation) {
try {
return operation.get()
} catch(RetryableException e) {
maxRetries--
if(maxRetries > 0) {
Thread.sleep(waitMs)
return (T) retry(maxRetries, waitMs, operation)
} else {
throw new Exception("Operation exceed maximum amount of retries", e.cause)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ class AppCenterConsts {
static PropertyLookup owner = new PropertyLookup("APP_CENTER_OWNER", "appCenter.owner", null)
static PropertyLookup applicationIdentifier = new PropertyLookup("APP_CENTER_APPLICATION_IDENTIFIER", "appCenter.applicationIdentifier", null)

static PropertyLookup defaultDestinations = new PropertyLookup("APP_CENTER_DEFAULT_DESTINATIONS", "appCenter.defaultDestinations", "Collaborators")
static PropertyLookup defaultDestinations = new PropertyLookup("APP_CENTER_DEFAULT_DESTINATIONS", "appCenter.defaultDestinations", "Collaborators")

static PropertyLookup publishEnabled = new PropertyLookup("APP_CENTER_PUBLISH_ENABLED", "appCenter.publishEnabled", true)
static PropertyLookup retryTimeout = new PropertyLookup("APP_CENTER_RETRY_TIMEOUT", "appCenter.retryTimeout", 1000 * 60)
static PropertyLookup retryCount = new PropertyLookup("APP_CENTER_RETRY_COUNT", "appCenter.retryCount", 30)
static PropertyLookup binary = new PropertyLookup("APP_CENTER_BINARY", "appCenter.binary", null)
static PropertyLookup releaseNotes = new PropertyLookup("APP_CENTER_RELEASE_NOTES", "appCenter.releaseNotes", null)
}
26 changes: 22 additions & 4 deletions src/main/groovy/wooga/gradle/appcenter/AppCenterPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package wooga.gradle.appcenter

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.internal.provider.MissingValueException
import org.gradle.api.publish.plugins.PublishingPlugin
import wooga.gradle.appcenter.internal.DefaultAppCenterPluginExtension

Expand All @@ -38,8 +40,8 @@ class AppCenterPlugin implements Plugin<Project> {
createAndConfigureTasks(project, extension)
}

protected static AppCenterPluginExtension createAndConfigureExtension(Project project) {
def extension = project.extensions.create(AppCenterPluginExtension, EXTENSION_NAME, DefaultAppCenterPluginExtension)
protected static DefaultAppCenterPluginExtension createAndConfigureExtension(Project project) {
def extension = project.extensions.create(AppCenterPluginExtension, EXTENSION_NAME, DefaultAppCenterPluginExtension) as DefaultAppCenterPluginExtension

extension.defaultDestinations.set(AppCenterConsts.defaultDestinations.getStringValueProvider(project)
.map({
Expand All @@ -54,10 +56,22 @@ class AppCenterPlugin implements Plugin<Project> {
extension.retryTimeout.convention(AppCenterConsts.retryTimeout.getValueProvider(project, {Long.parseLong(it)}))
extension.retryCount.convention(AppCenterConsts.retryCount.getIntegerValueProvider(project))

extension
def artifactFile = extension.artifact.map { PublishArtifact it ->
try {
return project.layout.projectDirectory.file(it.file.absolutePath)
//if the backing of artifact.file is a provider it just tries to resolve it, and
// if there is nothing yet in the provider, it throws
} catch (MissingValueException _) {
return null
}
}
extension.binary.convention(artifactFile)
extension.releaseNotes.convention(AppCenterConsts.releaseNotes.getStringValueProvider(project))

return extension
}

private static void createAndConfigureTasks(Project project, AppCenterPluginExtension extension) {
private static void createAndConfigureTasks(Project project, DefaultAppCenterPluginExtension extension) {
def tasks = project.tasks

def publishAppCenter = tasks.register(PUBLISH_APP_CENTER_TASK_NAME, AppCenterUploadTask, { t ->
Expand All @@ -73,6 +87,10 @@ class AppCenterPlugin implements Plugin<Project> {
t.owner.convention(extension.owner)
t.retryCount.convention(extension.retryCount)
t.retryTimeout.convention(extension.retryTimeout)
t.binary.convention(extension.binary)
if(extension.artifact.present && !t.binary.present) {
dependsOn(extension.artifact.get().buildDependencies)
}
}
project.afterEvaluate {
if (extension.isPublishEnabled().get()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,42 @@

package wooga.gradle.appcenter


import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider

trait AppCenterPluginExtension implements AppCenterSpec {

abstract void artifact(Provider<PublishArtifact> artifact);
abstract void artifact(PublishArtifact artifact);

private final Property<String> releaseNotes = objects.property(String)

Property<String> getReleaseNotes() {
releaseNotes
}

void setReleaseNotes(Provider<String> value) {
releaseNotes.set(value)
}

private final RegularFileProperty binary = objects.fileProperty()

RegularFileProperty getBinary() {
binary
}

void setBinary(Provider<RegularFile> value) {
binary.set(value)
}

void setBinary(File value) {
binary.set(value)
}

// TODO: Refactor, deprecate to use `destinations` instead?
private final ListProperty<Map<String, String>> defaultDestinations = objects.listProperty(Map)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,29 @@
package wooga.gradle.appcenter.internal

import org.gradle.api.Project
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import wooga.gradle.appcenter.AppCenterPluginExtension

class DefaultAppCenterPluginExtension implements AppCenterPluginExtension {

DefaultAppCenterPluginExtension() {
private final Project project

final Property<? extends PublishArtifact> artifact = objects.property(PublishArtifact)

DefaultAppCenterPluginExtension(Project project) {
this.project = project
}


@Override
void artifact(Provider<PublishArtifact> artifact) {
this.artifact.set(artifact)
}

@Override
void artifact(PublishArtifact artifact) {
this.artifact.set(project.provider{ artifact })
}
}
Loading

0 comments on commit a8fe5b4

Please sign in to comment.