diff --git a/src/main/groovy/com/deploygate/gradle/plugins/DeployGatePlugin.groovy b/src/main/groovy/com/deploygate/gradle/plugins/DeployGatePlugin.groovy index 72497e62..2dbb03e4 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/DeployGatePlugin.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/DeployGatePlugin.groovy @@ -68,11 +68,12 @@ class DeployGatePlugin implements Plugin { processor.registerDeclarationAwareUploadApkTask(variantOrCustomName) if (AndroidGradlePlugin.isAppBundleSupported()) { - // TODO create tasks for app bundle + processor.registerDeclarationAwareUploadAabTask(variantOrCustomName) } } processor.registerAggregatedDeclarationAwareUploadApkTask(processor.declaredNames) + processor.registerAggregatedDeclarationAwareUploadAabTask(processor.declaredNames) if (!processor.canProcessVariantAware()) { project.logger.warn("DeployGate Gradle Plugin is stopped because Android Gradle Plugin must be applied before.") @@ -85,7 +86,7 @@ class DeployGatePlugin implements Plugin { processor.registerVariantAwareUploadApkTask(variantProxy) if (AndroidGradlePlugin.isAppBundleSupported()) { - // TODO create tasks for app bundle + processor.registerVariantAwareUploadAabTask(variantProxy) } } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/Processor.groovy b/src/main/groovy/com/deploygate/gradle/plugins/Processor.groovy index 2496edc2..d544dcc0 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/Processor.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/Processor.groovy @@ -25,10 +25,16 @@ class Processor { private final LogoutTaskFactory logoutTaskFactory @Nonnull - private final UploadApkTaskFactory applicationVariantBasedUploadApkTaskFactory + private final UploadArtifactTaskFactory applicationVariantBasedUploadApkTaskFactory @Nonnull - private final UploadApkTaskFactory stringBasedUploadApkTaskFactory + private final UploadArtifactTaskFactory applicationVariantBasedUploadAabTaskFactory + + @Nonnull + private final UploadArtifactTaskFactory stringBasedUploadApkTaskFactory + + @Nonnull + private final UploadArtifactTaskFactory stringBasedUploadAabTaskFactory def declaredNames = new HashSet() @@ -38,7 +44,9 @@ class Processor { new LoginTaskFactoryImpl(project), new LogoutTaskFactoryImpl(project), new AGPBasedUploadApkTaskFactory(project), - new DSLBasedUploadApkTaskFactory(project) + new AGPBasedUploadAabTaskFactory(project), + new DSLBasedUploadApkTaskFactory(project), + new DSLBasedUploadAabTaskFactory(project) ) } @@ -47,14 +55,18 @@ class Processor { @Nonnull Project project, @Nonnull LoginTaskFactory loginTaskFactory, @Nonnull LogoutTaskFactory logoutTaskFactory, - @Nonnull UploadApkTaskFactory applicationVariantBasedUploadApkTaskFactory, - @Nonnull UploadApkTaskFactory stringBasedUploadApkTaskFactory + @Nonnull UploadArtifactTaskFactory applicationVariantBasedUploadApkTaskFactory, + @Nonnull UploadArtifactTaskFactory applicationVariantBasedUploadAabTaskFactory, + @Nonnull UploadArtifactTaskFactory stringBasedUploadApkTaskFactory, + @Nonnull UploadArtifactTaskFactory stringBasedUploadAabTaskFactory ) { this.project = project this.loginTaskFactory = loginTaskFactory this.logoutTaskFactory = logoutTaskFactory this.applicationVariantBasedUploadApkTaskFactory = applicationVariantBasedUploadApkTaskFactory + this.applicationVariantBasedUploadAabTaskFactory = applicationVariantBasedUploadAabTaskFactory this.stringBasedUploadApkTaskFactory = stringBasedUploadApkTaskFactory + this.stringBasedUploadAabTaskFactory = stringBasedUploadAabTaskFactory } boolean canProcessVariantAware() { @@ -79,11 +91,21 @@ class Processor { } def registerDeclarationAwareUploadApkTask(String variantOrCustomName) { - stringBasedUploadApkTaskFactory.registerUploadApkTask(variantOrCustomName, *dependencyAncestorOfUploadTaskNames) + stringBasedUploadApkTaskFactory.registerUploadArtifactTask(variantOrCustomName, *dependencyAncestorOfUploadTaskNames) + } + + def registerDeclarationAwareUploadAabTask(String variantOrCustomName) { + stringBasedUploadAabTaskFactory.registerUploadArtifactTask(variantOrCustomName, *dependencyAncestorOfUploadTaskNames) } def registerAggregatedDeclarationAwareUploadApkTask(Collection variantOrCustomNames) { - stringBasedUploadApkTaskFactory.registerAggregatedUploadApkTask(variantOrCustomNames.collect { + stringBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask(variantOrCustomNames.collect { + DeployGateTaskFactory.uploadApkTaskName(it) + }) + } + + def registerAggregatedDeclarationAwareUploadAabTask(Collection variantOrCustomNames) { + stringBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask(variantOrCustomNames.collect { DeployGateTaskFactory.uploadApkTaskName(it) }) } @@ -94,7 +116,16 @@ class Processor { return } - applicationVariantBasedUploadApkTaskFactory.registerUploadApkTask(variant, *dependencyAncestorOfUploadTaskNames) + applicationVariantBasedUploadApkTaskFactory.registerUploadArtifactTask(variant, *dependencyAncestorOfUploadTaskNames) + } + + def registerVariantAwareUploadAabTask(@Nonnull IApplicationVariant variant) { + if (!canProcessVariantAware()) { + project.logger.error("android gradle plugin not found but tried to create android-specific tasks. Ignored...") + return + } + + applicationVariantBasedUploadAabTaskFactory.registerUploadArtifactTask(variant, *dependencyAncestorOfUploadTaskNames) } @VisibleForTesting diff --git a/src/main/groovy/com/deploygate/gradle/plugins/artifacts/AabInfo.groovy b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/AabInfo.groovy new file mode 100644 index 00000000..2ce74839 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/AabInfo.groovy @@ -0,0 +1,12 @@ +package com.deploygate.gradle.plugins.artifacts + +import javax.annotation.Nonnull +import javax.annotation.Nullable + +interface AabInfo { + @Nonnull + String getVariantName() + + @Nullable + File getAabFile() +} \ No newline at end of file diff --git a/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DefaultPresetAabInfo.groovy b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DefaultPresetAabInfo.groovy new file mode 100644 index 00000000..35dcb640 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DefaultPresetAabInfo.groovy @@ -0,0 +1,9 @@ +package com.deploygate.gradle.plugins.artifacts + +import javax.annotation.Nonnull + +class DefaultPresetAabInfo extends DirectAabInfo { + DefaultPresetAabInfo(@Nonnull String variantName) { + super(variantName, null) + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DirectAabInfo.groovy b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DirectAabInfo.groovy new file mode 100644 index 00000000..488992e2 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/DirectAabInfo.groovy @@ -0,0 +1,35 @@ +package com.deploygate.gradle.plugins.artifacts + +import com.google.common.annotations.VisibleForTesting + +import javax.annotation.Nonnull +import javax.annotation.Nullable + +@VisibleForTesting +class DirectAabInfo implements AabInfo { + @Nonnull + private final String variantName + @Nullable + private final File aabFile + + DirectAabInfo(@Nonnull String variantName, @Nullable File aabFile) { + this.variantName = variantName + this.aabFile = aabFile + + if (!variantName) { + throw new IllegalArgumentException("variantName must not be null or empty") + } + } + + @Override + @Nonnull + String getVariantName() { + return variantName + } + + @Override + @Nullable + File getAabFile() { + return aabFile + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/artifacts/PackageAppTaskCompat.groovy b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/PackageAppTaskCompat.groovy index a6c8ce2c..932a1e14 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/artifacts/PackageAppTaskCompat.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/artifacts/PackageAppTaskCompat.groovy @@ -1,7 +1,9 @@ package com.deploygate.gradle.plugins.artifacts + import com.deploygate.gradle.plugins.internal.agp.AndroidGradlePlugin import groovy.transform.PackageScope +import org.gradle.api.Project import javax.annotation.Nonnull @@ -10,8 +12,7 @@ class PackageAppTaskCompat { } @Nonnull - static ApkInfo getApkInfo(@Nonnull /* PackageApplication */ packageAppTask) { - String variantName = packageAppTask.name + static ApkInfo getApkInfo(@Nonnull /* PackageApplication */ packageAppTask, @Nonnull String variantName) { // outputScope is retrieved by the reflection Collection apkNames = packageAppTask.outputScope.apkDatas*.outputFileName File outputDir = packageAppTask.outputDirectory @@ -26,6 +27,26 @@ class PackageAppTaskCompat { ) } + @Nonnull + static AabInfo getAabInfo(@Nonnull /* PackageApplication */ packageAppTask, @Nonnull String variantName, @Nonnull Project project) { + final String aabName + + if (AndroidGradlePlugin.isAppBundleArchiveNameChanged()) { + // outputScope is retrieved by the reflection + Collection apkNames = packageAppTask.outputScope.apkDatas*.outputFileName + aabName = ((String) apkNames[0]).replaceFirst("\\.apk\$", ".aab") + } else { + aabName = "${project.properties["archivesBaseName"] as String}.aab" + } + + def outputDir = new File(project.buildDir, "outputs/bundle/${variantName}") + + return new DirectAabInfo( + variantName, + new File(outputDir, aabName), + ) + } + @PackageScope static boolean hasSigningConfig(packageAppTask) { if (!AndroidGradlePlugin.isSigningConfigCollectionSupported()) { diff --git a/src/main/groovy/com/deploygate/gradle/plugins/internal/agp/AndroidGradlePlugin.groovy b/src/main/groovy/com/deploygate/gradle/plugins/internal/agp/AndroidGradlePlugin.groovy index 3b82c5da..1d7eeb48 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/internal/agp/AndroidGradlePlugin.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/internal/agp/AndroidGradlePlugin.groovy @@ -1,5 +1,6 @@ package com.deploygate.gradle.plugins.internal.agp + import com.deploygate.gradle.plugins.internal.VersionString import org.gradle.api.Plugin import org.gradle.api.Project @@ -56,11 +57,20 @@ class AndroidGradlePlugin { return getVersion().major >= 4 || getVersion().major == 3 && getVersion().minor > 2 } + static boolean isAppBundleArchiveNameChanged() { + return getVersion().major >= 4 || getVersion().major == 3 && getVersion().minor >= 5 + } + @Nonnull static String androidAssembleTaskName(@Nonnull String variantName) { return "assemble${variantName.capitalize()}" } + @Nonnull + static String androidBundleTaskName(@Nonnull String variantName) { + return "bundle${variantName.capitalize()}" + } + /** * Get the AGP version from a classloader because `plugins` block will separate class loaders * diff --git a/src/main/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactory.groovy index 2b369dae..f806e079 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactory.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactory.groovy @@ -15,17 +15,33 @@ class TaskFactory { } @Nullable - final LazyConfigurableTask register(@Nonnull String taskName, @Nonnull Class klass, boolean allowExisting = true) { - def existingTask = project.tasks.findByName(taskName) + final LazyConfigurableTask register(@Nonnull String taskName, @Nonnull Class klass) { + def existingTask = findByName(taskName) if (existingTask) { - if (allowExisting) { - return new SingleTask(existingTask as T) - } else { - return null - } + return null } return GradleCompat.newLazyConfigurableTask(project, taskName, klass) } + + @Nullable + final LazyConfigurableTask registerOrFindBy(@Nonnull String taskName, @Nonnull Class klass) { + def existingTask = findByName(taskName) + + if (existingTask) { + return new SingleTask(existingTask as T) + } + + return GradleCompat.newLazyConfigurableTask(project, taskName, klass) + } + + final boolean exists(@Nonnull String taskName) { + return findByName(taskName) + } + + @Nullable + private Task findByName(@Nonnull String taskName) { + return project.tasks.findByName(taskName) + } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTask.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTask.groovy new file mode 100644 index 00000000..f067f075 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTask.groovy @@ -0,0 +1,35 @@ +package com.deploygate.gradle.plugins.tasks + +import com.deploygate.gradle.plugins.artifacts.AabInfo +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.tasks.factory.DeployGateTaskFactory +import org.gradle.api.tasks.TaskAction + +import javax.annotation.Nonnull + +class UploadAabTask extends UploadArtifactTask { + static Configuration createConfiguration(@Nonnull NamedDeployment deployment, @Nonnull AabInfo aabInfo) { + return new Configuration( + artifactFile: deployment.sourceFile ?: aabInfo.aabFile, + isSigningReady: false, + isUniversalApk: false, + uploadParams: createUploadParams(deployment) + ) + } + + @TaskAction + void doUpload() { + super.doUpload() + } + + @Override + void applyTaskProfile() { + setDescription("Deploy bundled $variantName to DeployGate") + + group = DeployGateTaskFactory.GROUP_NAME + } + + @Override + void runArtifactSpecificVerification() { + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTask.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTask.groovy index 4200f2e2..06e7f893 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTask.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTask.groovy @@ -1,98 +1,28 @@ package com.deploygate.gradle.plugins.tasks -import com.deploygate.gradle.plugins.Config import com.deploygate.gradle.plugins.artifacts.ApkInfo import com.deploygate.gradle.plugins.dsl.NamedDeployment import com.deploygate.gradle.plugins.tasks.factory.DeployGateTaskFactory -import com.deploygate.gradle.plugins.utils.BrowserUtils -import com.deploygate.gradle.plugins.utils.HTTPBuilderFactory -import com.google.common.annotations.VisibleForTesting -import groovyx.net.http.ContentType -import groovyx.net.http.HttpResponseDecorator -import groovyx.net.http.Method -import org.apache.http.entity.mime.MultipartEntity -import org.apache.http.entity.mime.content.FileBody -import org.apache.http.entity.mime.content.StringBody -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException import org.gradle.api.tasks.TaskAction import javax.annotation.Nonnull -import javax.annotation.Nullable -import java.nio.charset.Charset - -class UploadApkTask extends DefaultTask { - static class Configuration { - boolean isSigningReady - boolean isUniversalApk - - File apkFile - String message - String distributionKey - String releaseNote - String visibility - - HashMap toUploadParams() { - HashMap params = new HashMap() - if (message != null) { - params.put("message", message) - } - if (distributionKey != null) { - params.put("distribution_key", distributionKey) - } - if (releaseNote != null) { - params.put("release_note", releaseNote) - } - if (visibility != null) { - params.put("visibility", visibility) - } - return params - } - } +class UploadApkTask extends UploadArtifactTask { static Configuration createConfiguration(@Nonnull NamedDeployment deployment, @Nonnull ApkInfo apkInfo) { return new Configuration( + artifactFile: deployment.sourceFile ?: apkInfo.apkFile, isSigningReady: apkInfo.isSigningReady(), isUniversalApk: apkInfo.isUniversalApk(), - apkFile: deployment.sourceFile ?: apkInfo.apkFile, - message: deployment.message, - distributionKey: deployment.distribution?.key, - releaseNote: deployment.distribution?.releaseNote, - visibility: deployment.visibility + uploadParams: createUploadParams(deployment) ) } - @Nullable - private String variantName - - private Configuration configuration - - void setVariantName(@Nonnull String variantName) { - if (this.variantName && this.variantName != variantName) { - throw new IllegalStateException("different variant name cannot be assigned") - } - - this.variantName = variantName - } - - @VisibleForTesting - @Nullable - String getVariantName() { - return variantName - } - - void setConfiguration(@Nonnull Configuration configuration) { - if (!this.variantName) { - throw new IllegalStateException("variant name must be set first") - } - - if (this.configuration) { - logger.debug("$variantName upload apk task configuration has been overwritten") - } - - this.configuration = configuration + @TaskAction + void doUpload() { + super.doUpload() } + @Override void applyTaskProfile() { setDescription("Deploy assembled $variantName to DeployGate") @@ -106,88 +36,10 @@ class UploadApkTask extends DefaultTask { } } - @TaskAction - def uploadApkToServer() { + @Override + void runArtifactSpecificVerification() { if (!configuration.isSigningReady) { throw new IllegalStateException('Cannot upload a build without code signature to DeployGate') } - - if (!configuration.apkFile) { - throw new IllegalStateException("An apk file to be upload not specified.") - } - - if (!configuration.apkFile.exists()) { - throw new IllegalStateException("APK file ${configuration.apkFile} was not found. If you are using Android Build Tools >= 3.0.0, you need to set `sourceFile` in your build.gradle. See https://docs.deploygate.com/docs/gradle-plugin") - } - - def appOwnerName = getAppOwnerName() - def apiToken = getApiToken() - - onBeforeUpload() - - def response = postRequestToUpload(appOwnerName, apiToken, configuration.apkFile, configuration.toUploadParams()) - - handleResponse(response, response.data) - } - - void onBeforeUpload() { - project.deploygate.notifyServer 'start_upload', ['length': Long.toString(configuration.apkFile.length())] - } - - def handleResponse(HttpResponseDecorator response, data) { - if (!(200 <= response.status && response.status < 300) || data.error) { - throw new GradleException("${variantName} failed due to ${data.message}") - } - - if (data.error) - project.deploygate.notifyServer 'upload_finished', ['error': true, message: data.message] - else { - def sent = project.deploygate.notifyServer 'upload_finished', ['path': data.results.path] - - if (!sent && (Config.shouldOpenAppDetailAfterUpload() || data.results.revision == 1)) { - BrowserUtils.openBrowser "${project.deploygate.endpoint}${data.results.path}" - } - } - } - - @VisibleForTesting - @Nonnull - String getApiToken() { - def apiToken = project.deploygate.apiToken - - if (!apiToken?.trim()) { - throw new GradleException('apiToken is missing. Please enter the token.') - } - - apiToken.trim() - } - - @VisibleForTesting - @Nonnull - String getAppOwnerName() { - def appOwnerName = project.deploygate.appOwnerName - - if (!appOwnerName?.trim()) { - throw new GradleException('appOwnerName is missing. Please enter the token.') - } - - appOwnerName.trim() - } - - private HttpResponseDecorator postRequestToUpload(String appOwnerName, String apiToken, File apkFile, Map params) { - MultipartEntity entity = new MultipartEntity() - Charset charset = Charset.forName('UTF-8') - - entity.addPart("file", new FileBody(apkFile.getAbsoluteFile())) - entity.addPart("token", new StringBody(apiToken, charset)) - - for (String key : params.keySet()) { - entity.addPart(key, new StringBody(params.get(key), charset)) - } - - HTTPBuilderFactory.restClient(project.deploygate.endpoint).request(Method.POST, ContentType.JSON) { req -> - uri.path = "/api/users/${appOwnerName}/apps" - req.entity = entity - } as HttpResponseDecorator } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTask.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTask.groovy new file mode 100644 index 00000000..6e707907 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTask.groovy @@ -0,0 +1,205 @@ +package com.deploygate.gradle.plugins.tasks + +import com.deploygate.gradle.plugins.Config +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.utils.BrowserUtils +import com.deploygate.gradle.plugins.utils.HTTPBuilderFactory +import com.google.common.annotations.VisibleForTesting +import groovyx.net.http.ContentType +import groovyx.net.http.HttpResponseDecorator +import groovyx.net.http.HttpResponseException +import groovyx.net.http.Method +import org.apache.http.entity.mime.MultipartEntity +import org.apache.http.entity.mime.content.FileBody +import org.apache.http.entity.mime.content.StringBody +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException + +import javax.annotation.Nonnull +import javax.annotation.Nullable +import java.nio.charset.Charset + +abstract class UploadArtifactTask extends DefaultTask { + static class Configuration { + boolean isSigningReady + boolean isUniversalApk + + File artifactFile + + UploadParams uploadParams + } + + static class UploadParams { + String message + String distributionKey + String releaseNote + String visibility + + HashMap toMap() { + HashMap params = new HashMap() + if (message != null) { + params.put("message", message) + } + if (distributionKey != null) { + params.put("distribution_key", distributionKey) + } + if (releaseNote != null) { + params.put("release_note", releaseNote) + } + if (visibility != null) { + params.put("visibility", visibility) + } + return params + } + } + + static UploadParams createUploadParams(@Nonnull NamedDeployment deployment) { + return new UploadParams( + message: deployment.message, + distributionKey: deployment.distribution?.key, + releaseNote: deployment.distribution?.releaseNote, + visibility: deployment.visibility + ) + } + + @Nullable + private String variantName + + Configuration configuration + + private def lazyPackageApplication + + void setVariantName(@Nonnull String variantName) { + if (this.variantName && this.variantName != variantName) { + throw new IllegalStateException("different variant name cannot be assigned") + } + + this.variantName = variantName + } + + @Nullable + String getVariantName() { + return variantName + } + + void setConfiguration(@Nonnull Configuration configuration) { + if (!this.variantName) { + throw new IllegalStateException("variant name must be set first") + } + + if (this.configuration) { + logger.debug("$variantName upload artifact (${this.getClass().simpleName}) task configuration has been overwritten") + } + + this.configuration = configuration + } + + void setLazyPackageApplication(lazyPackageApplication) { + this.lazyPackageApplication = lazyPackageApplication + } + + // Add TaskAction annotation in overrider classes + void doUpload() { + if (lazyPackageApplication) { + // evaluate surely + // ref: https://github.com/DeployGate/gradle-deploygate-plugin/issues/86 + lazyPackageApplication.get() + logger.debug("$variantName's package application task has been evaluated") + } else { + logger.debug("$variantName's package application task is not found") + } + + runArtifactSpecificVerification() + uploadArtifactToServer() + } + + abstract void applyTaskProfile() + + abstract void runArtifactSpecificVerification() + + private void uploadArtifactToServer() { + if (!configuration.artifactFile) { + throw new IllegalStateException("An artifact file to be upload not specified.") + } + + if (!configuration.artifactFile.exists()) { + throw new IllegalStateException("An artifact file (${configuration.artifactFile}) was not found. If you are using Android Build Tools >= 3.0.0, you need to set `sourceFile` in your build.gradle. See https://docs.deploygate.com/docs/gradle-plugin") + } + + def appOwnerName = getAppOwnerName() + def apiToken = getApiToken() + + onBeforeUpload() + + def response = postRequestToUpload(appOwnerName, apiToken, configuration.artifactFile, configuration.uploadParams) + + handleResponse(response, response.data) + } + + private void onBeforeUpload() { + project.deploygate.notifyServer 'start_upload', ['length': Long.toString(configuration.artifactFile.length())] + } + + private void handleResponse(HttpResponseDecorator response, data) { + if (!(200 <= response.status && response.status < 300) || data.error) { + throw new GradleException("${variantName} failed due to ${data.message}") + } + + if (data.error) + project.deploygate.notifyServer 'upload_finished', ['error': true, message: data.message] + else { + def sent = project.deploygate.notifyServer 'upload_finished', ['path': data.results.path] + + if (!sent && (Config.shouldOpenAppDetailAfterUpload() || data.results.revision == 1)) { + BrowserUtils.openBrowser "${project.deploygate.endpoint}${data.results.path}" + } + } + } + + @Nonnull + @VisibleForTesting + String getApiToken() { + def apiToken = project.deploygate.apiToken + + if (!apiToken?.trim()) { + throw new GradleException('apiToken is missing. Please enter the token.') + } + + apiToken.trim() + } + + @Nonnull + @VisibleForTesting + String getAppOwnerName() { + def appOwnerName = project.deploygate.appOwnerName + + if (!appOwnerName?.trim()) { + throw new GradleException('appOwnerName is missing. Please enter the token.') + } + + appOwnerName.trim() + } + + private HttpResponseDecorator postRequestToUpload(String appOwnerName, String apiToken, File artifactFile, UploadParams uploadParams) { + MultipartEntity entity = new MultipartEntity() + Charset charset = Charset.forName('UTF-8') + + entity.addPart("file", new FileBody(artifactFile.getAbsoluteFile())) + entity.addPart("token", new StringBody(apiToken, charset)) + + def params = uploadParams.toMap() + + for (String key : params.keySet()) { + entity.addPart(key, new StringBody(params.get(key), charset)) + } + + try { + HTTPBuilderFactory.restClient(project.deploygate.endpoint).request(Method.POST, ContentType.JSON) { req -> + uri.path = "/api/users/${appOwnerName}/apps" + req.entity = entity + } as HttpResponseDecorator + } catch (HttpResponseException e) { + e.response + } + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactory.groovy new file mode 100644 index 00000000..102987f8 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactory.groovy @@ -0,0 +1,50 @@ +package com.deploygate.gradle.plugins.tasks.factory + + +import com.deploygate.gradle.plugins.artifacts.PackageAppTaskCompat +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.internal.agp.IApplicationVariant +import com.deploygate.gradle.plugins.tasks.UploadAabTask +import org.gradle.api.Project + +import javax.annotation.Nonnull + +import static com.deploygate.gradle.plugins.internal.agp.AndroidGradlePlugin.androidBundleTaskName + +class AGPBasedUploadAabTaskFactory extends DeployGateTaskFactory implements UploadArtifactTaskFactory { + AGPBasedUploadAabTaskFactory(@Nonnull Project project) { + super(project) + } + + @Override + void registerUploadArtifactTask(@Nonnull IApplicationVariant applicationVariant, Object... dependsOn) { + String variantName = applicationVariant.name + + // depends on other task provider, so we need to get a task right now. + def dgTask = taskFactory.registerOrFindBy(uploadAabTaskName(variantName), UploadAabTask).get() + + final NamedDeployment deployment = deployGateExtension.findDeploymentByName(variantName) + + dgTask.variantName = variantName + + if (deployment?.skipAssemble) { + dgTask.dependsOn(dependsOn) + } else { + dgTask.dependsOn([androidBundleTaskName(variantName), *dependsOn].flatten()) + } + + dgTask.lazyPackageApplication = applicationVariant.lazyPackageApplication() + + applicationVariant.lazyPackageApplication().configure { packageAppTask -> + def aabInfo = PackageAppTaskCompat.getAabInfo(packageAppTask, variantName, project) + + dgTask.configuration = UploadAabTask.createConfiguration(deployment, aabInfo) + dgTask.applyTaskProfile() + } + } + + @Override + void registerAggregatedUploadArtifactTask(Object... dependsOn) { + throw new IllegalAccessException("this method is not allowed to be called") + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactory.groovy index 476f2d64..a7bdf30c 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactory.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactory.groovy @@ -10,17 +10,17 @@ import javax.annotation.Nonnull import static com.deploygate.gradle.plugins.internal.agp.AndroidGradlePlugin.androidAssembleTaskName -class AGPBasedUploadApkTaskFactory extends DeployGateTaskFactory implements UploadApkTaskFactory { +class AGPBasedUploadApkTaskFactory extends DeployGateTaskFactory implements UploadArtifactTaskFactory { AGPBasedUploadApkTaskFactory(@Nonnull Project project) { super(project) } @Override - void registerUploadApkTask(@Nonnull IApplicationVariant applicationVariant, Object... dependsOn) { + void registerUploadArtifactTask(@Nonnull IApplicationVariant applicationVariant, Object... dependsOn) { String variantName = applicationVariant.name // depends on other task provider, so we need to get a task right now. - def dgTask = taskFactory.register(uploadApkTaskName(variantName), UploadApkTask).get() + def dgTask = taskFactory.registerOrFindBy(uploadApkTaskName(variantName), UploadApkTask).get() final NamedDeployment deployment = deployGateExtension.findDeploymentByName(variantName) @@ -32,23 +32,19 @@ class AGPBasedUploadApkTaskFactory extends DeployGateTaskFactory implements Uplo dgTask.dependsOn([androidAssembleTaskName(variantName), *dependsOn].flatten()) } + dgTask.lazyPackageApplication = applicationVariant.lazyPackageApplication() + applicationVariant.lazyPackageApplication().configure { packageAppTask -> - def apkInfo = PackageAppTaskCompat.getApkInfo(packageAppTask) + def apkInfo = PackageAppTaskCompat.getApkInfo(packageAppTask, variantName) def configuration = UploadApkTask.createConfiguration(deployment, apkInfo) dgTask.configuration = configuration dgTask.applyTaskProfile() } - - if (deployment?.skipAssemble) { - // a package application provider may not be evaluated in some cases. - // ref: https://github.com/DeployGate/gradle-deploygate-plugin/issues/86 - applicationVariant.lazyPackageApplication().get() - } } @Override - void registerAggregatedUploadApkTask(Object... dependsOn) { + void registerAggregatedUploadArtifactTask(Object... dependsOn) { throw new IllegalAccessException("this method is not allowed to be called") } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactory.groovy new file mode 100644 index 00000000..a9fc3c8e --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactory.groovy @@ -0,0 +1,67 @@ +package com.deploygate.gradle.plugins.tasks.factory + +import com.deploygate.gradle.plugins.artifacts.DefaultPresetAabInfo +import com.deploygate.gradle.plugins.artifacts.DefaultPresetApkInfo +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.tasks.UploadAabTask +import com.deploygate.gradle.plugins.tasks.UploadApkTask +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.Project + +import javax.annotation.Nonnull + +class DSLBasedUploadAabTaskFactory extends DeployGateTaskFactory implements UploadArtifactTaskFactory { + DSLBasedUploadAabTaskFactory(@Nonnull Project project) { + super(project) + } + + @Override + void registerUploadArtifactTask(@Nonnull String variantNameOrCustomName, Object... dependsOn) { + def lazyUploadAabTask = taskFactory.register(uploadAabTaskName(variantNameOrCustomName), UploadAabTask) + + if (!lazyUploadAabTask) { + project.logger.debug("It sounds $variantNameOrCustomName's upload aab task has been already registered by me or other factories") + return + } + + if (!deployGateExtension.hasDeployment(variantNameOrCustomName)) { + project.logger.error("No associated deployment to $variantNameOrCustomName has been detected") + project.logger.error("Please report this problem from https://github.com/DeployGate/gradle-deploygate-plugin/issues") + + throw new GradleException("$variantNameOrCustomName could not be handled by DeployGate plugin") + } + + final NamedDeployment deployment = deployGateExtension.findDeploymentByName(variantNameOrCustomName) + + if (!deployment.skipAssemble) { + project.logger.debug("$variantNameOrCustomName required assmble but ignored") + } + + lazyUploadAabTask.configure { dgTask -> + dgTask.variantName = variantNameOrCustomName + dgTask.dependsOn(dependsOn) + } + + def aabInfo = new DefaultPresetAabInfo(variantNameOrCustomName) + def configuration = UploadAabTask.createConfiguration(deployment, aabInfo) + + lazyUploadAabTask.configure { dgTask -> + dgTask.configuration = configuration + dgTask.applyTaskProfile() + } + } + + @Override + void registerAggregatedUploadArtifactTask(Object... dependsOn) { + if (!dependsOn?.flatten()) { + project.logger.debug("skipped register aggregation tasks") + return + } + + taskFactory.registerOrFindBy(SUFFIX_AAB_TASK_NAME, DefaultTask).configure { dgTask -> + dgTask.group = GROUP_NAME + dgTask.dependsOn(dependsOn.flatten()) + } + } +} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactory.groovy index d375f320..e896d13b 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactory.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactory.groovy @@ -9,14 +9,14 @@ import org.gradle.api.Project import javax.annotation.Nonnull -class DSLBasedUploadApkTaskFactory extends DeployGateTaskFactory implements UploadApkTaskFactory { +class DSLBasedUploadApkTaskFactory extends DeployGateTaskFactory implements UploadArtifactTaskFactory { DSLBasedUploadApkTaskFactory(@Nonnull Project project) { super(project) } @Override - void registerUploadApkTask(@Nonnull String variantNameOrCustomName, Object... dependsOn) { - def lazyUploadApkTask = taskFactory.register(uploadApkTaskName(variantNameOrCustomName), UploadApkTask, false) + void registerUploadArtifactTask(@Nonnull String variantNameOrCustomName, Object... dependsOn) { + def lazyUploadApkTask = taskFactory.register(uploadApkTaskName(variantNameOrCustomName), UploadApkTask) if (!lazyUploadApkTask) { project.logger.debug("It sounds $variantNameOrCustomName's upload apk task has been already registered by me or other factories") @@ -51,13 +51,13 @@ class DSLBasedUploadApkTaskFactory extends DeployGateTaskFactory implements Uplo } @Override - void registerAggregatedUploadApkTask(Object... dependsOn) { + void registerAggregatedUploadArtifactTask(Object... dependsOn) { if (!dependsOn?.flatten()) { project.logger.debug("skipped register aggregation tasks") return } - taskFactory.register(AGGREGATION_TASK_NAME, DefaultTask).configure { dgTask -> + taskFactory.registerOrFindBy(SUFFIX_APK_TASK_NAME, DefaultTask).configure { dgTask -> dgTask.group = GROUP_NAME dgTask.dependsOn(dependsOn.flatten()) } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DeployGateTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DeployGateTaskFactory.groovy index cf9b23d6..3d300ab6 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DeployGateTaskFactory.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/DeployGateTaskFactory.groovy @@ -8,11 +8,17 @@ import javax.annotation.Nonnull abstract class DeployGateTaskFactory { public static final String GROUP_NAME = 'DeployGate' - public static String AGGREGATION_TASK_NAME = "uploadDeployGate" + public static String SUFFIX_APK_TASK_NAME = "uploadDeployGate" + public static String SUFFIX_AAB_TASK_NAME = "uploadDeployGateAab" @Nonnull static String uploadApkTaskName(@Nonnull String variantName) { - return "$AGGREGATION_TASK_NAME${variantName.capitalize()}" + return "$SUFFIX_APK_TASK_NAME${variantName.capitalize()}" + } + + @Nonnull + static String uploadAabTaskName(@Nonnull String variantName) { + return "$SUFFIX_AAB_TASK_NAME${variantName.capitalize()}" } @Nonnull diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LoginTaskFactoryImpl.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LoginTaskFactoryImpl.groovy index 9f7a1d80..015ceb61 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LoginTaskFactoryImpl.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LoginTaskFactoryImpl.groovy @@ -12,7 +12,7 @@ class LoginTaskFactoryImpl extends DeployGateTaskFactory implements LoginTaskFac @Override void registerLoginTask() { - taskFactory.register(TASK_NAME, LoginTask).configure { + taskFactory.registerOrFindBy(TASK_NAME, LoginTask).configure { it.group = GROUP_NAME } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LogoutTaskFactoryImpl.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LogoutTaskFactoryImpl.groovy index 053ee3e2..60b60e08 100644 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LogoutTaskFactoryImpl.groovy +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/LogoutTaskFactoryImpl.groovy @@ -12,7 +12,7 @@ class LogoutTaskFactoryImpl extends DeployGateTaskFactory implements LogoutTaskF @Override void registerLogoutTask() { - taskFactory.register(TASK_NAME, LogoutTask).configure { + taskFactory.registerOrFindBy(TASK_NAME, LogoutTask).configure { it.group = GROUP_NAME } } diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadApkTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadApkTaskFactory.groovy deleted file mode 100644 index ed63f4e3..00000000 --- a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadApkTaskFactory.groovy +++ /dev/null @@ -1,9 +0,0 @@ -package com.deploygate.gradle.plugins.tasks.factory - -import javax.annotation.Nonnull - -interface UploadApkTaskFactory { - void registerUploadApkTask(@Nonnull T variantOrVariantNameOrCustomName, Object... dependsOn) - - void registerAggregatedUploadApkTask(Object... dependsOn) -} diff --git a/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadArtifactTaskFactory.groovy b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadArtifactTaskFactory.groovy new file mode 100644 index 00000000..8da99948 --- /dev/null +++ b/src/main/groovy/com/deploygate/gradle/plugins/tasks/factory/UploadArtifactTaskFactory.groovy @@ -0,0 +1,9 @@ +package com.deploygate.gradle.plugins.tasks.factory + +import javax.annotation.Nonnull + +interface UploadArtifactTaskFactory { + void registerUploadArtifactTask(@Nonnull T variantOrVariantNameOrCustomName, Object... dependsOn) + + void registerAggregatedUploadArtifactTask(Object... dependsOn) +} diff --git a/src/test/acceptance/com/deploygate/gradle/plugins/AcceptanceTestBaseSpec.groovy b/src/test/acceptance/com/deploygate/gradle/plugins/AcceptanceTestBaseSpec.groovy index f79f33f2..2f2f293e 100644 --- a/src/test/acceptance/com/deploygate/gradle/plugins/AcceptanceTestBaseSpec.groovy +++ b/src/test/acceptance/com/deploygate/gradle/plugins/AcceptanceTestBaseSpec.groovy @@ -45,6 +45,15 @@ abstract class AcceptanceTestBaseSpec extends Specification { abstract AGPEnv[] getTestTargetAGPEnvs() + AGPEnv[] getAppBundleTestTargetAGPEnvs() { + return testTargetAGPEnvs.findAll { isAppBundleSupport(it.agpVersion) } + } + + boolean isAppBundleSupport(String agpVersion) { + def version = VersionString.tryParse(agpVersion) + return version.major >= 4 || version.major == 3 && version.minor > 1 + } + def setup() { testAndroidProject = new TestAndroidProject(testProjectDir) testDeployGatePlugin = new TestDeployGatePlugin() @@ -90,6 +99,28 @@ abstract class AcceptanceTestBaseSpec extends Specification { runner.withArguments("existsTask", "-PtaskName=uploadDeployGateFlavor2Flavor4Release").build() runner.withArguments("existsTask", "-PtaskName=uploadDeployGateCustomApk").build() + if (isAppBundleSupport(agpVersion)) { + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor3Debug").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor3Debug").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor4Debug").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor4Debug").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor3Release").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor3Release").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor4Release").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor4Release").build() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabCustomApk").build() + } else { + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor3Debug").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor3Debug").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor4Debug").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor4Debug").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor3Release").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor3Release").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor1Flavor4Release").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabFlavor2Flavor4Release").buildAndFail() + runner.withArguments("existsTask", "-PtaskName=uploadDeployGateAabCustomApk").buildAndFail() + } + where: agpEnv << testTargetAGPEnvs agpVersion = agpEnv.agpVersion as String @@ -126,6 +157,12 @@ abstract class AcceptanceTestBaseSpec extends Specification { result.contains("uploadDeployGateFlavor1Flavor4Debug") result.contains("uploadDeployGateFlavor2Flavor4Debug") result.contains("uploadDeployGateCustomApk") + // regardless of aab support + !result.contains("uploadDeployGateAabFlavor1Flavor3Release") + !result.contains("uploadDeployGateAabFlavor2Flavor3Release") + !result.contains("uploadDeployGateAabFlavor1Flavor4Release") + !result.contains("uploadDeployGateAabFlavor2Flavor4Release") + !result.contains("uploadDeployGateAabCustomApk") where: agpEnv << testTargetAGPEnvs @@ -134,7 +171,7 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "flavor1Flavor3Debug #agpVersion"() { + def "flavor1Flavor3Debug apk #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -168,7 +205,41 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "flavor2Flavor3Debug #agpVersion"() { + def "flavor1Flavor3Debug aab #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabFlavor1Flavor3Debug" /*, "--stacktrace" */) + + and: + def buildResult = runner.build() + def result = wireMockRule.findRequestsMatching(postRequestedFor(urlPathEqualTo("/api/users/appOwner/apps")).build()) + def request = result.requests.first() + + expect: + buildResult.task(":uploadDeployGateAabFlavor1Flavor3Debug").outcome == TaskOutcome.SUCCESS + result.requests.size() == 1 + request.getPart("token").body.asString() == "api token" + request.getPart("file").body.present + missingPart(request, "message") + missingPart(request, "distribution_key") + missingPart(request, "release_note") + missingPart(request, "visibility") + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + + @Unroll + def "flavor2Flavor3Debug apk #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -202,7 +273,41 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "flavor1Flavor4Debug #agpVersion"() { + def "flavor2Flavor3Debug aab #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabFlavor2Flavor3Debug" /*, "--stacktrace" */) + + and: + def buildResult = runner.build() + def result = wireMockRule.findRequestsMatching(postRequestedFor(urlPathEqualTo("/api/users/appOwner/apps")).build()) + def request = result.requests.first() + + expect: + buildResult.task(":uploadDeployGateAabFlavor2Flavor3Debug").outcome == TaskOutcome.SUCCESS + result.requests.size() == 1 + request.getPart("token").body.asString() == "api token" + request.getPart("file").body.present + request.getPart("message").body.asString() == "flavor2Flavor3Debug" + missingPart(request, "distribution_key") + missingPart(request, "release_note") + missingPart(request, "visibility") + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + + @Unroll + def "flavor1Flavor4Debug apk #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -236,7 +341,41 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "flavor2Flavor4Debug should fail unless assembling #agpVersion"() { + def "flavor1Flavor4Debug aab #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabFlavor1Flavor4Debug" /*, "--stacktrace" */) + + and: + def buildResult = runner.build() + def result = wireMockRule.findRequestsMatching(postRequestedFor(urlPathEqualTo("/api/users/appOwner/apps")).build()) + def request = result.requests.first() + + expect: + buildResult.task(":uploadDeployGateAabFlavor1Flavor4Debug").outcome == TaskOutcome.SUCCESS + result.requests.size() == 1 + request.getPart("token").body.asString() == "api token" + request.getPart("file").body.present + request.getPart("message").body.asString() == "flavor1Flavor4Debug" + missingPart(request, "distribution_key") + missingPart(request, "release_note") + missingPart(request, "visibility") + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + + @Unroll + def "flavor2Flavor4Debug apk should fail unless assembling #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -261,7 +400,32 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "flavor2Flavor4Debug require assembling #agpVersion"() { + def "flavor2Flavor4Debug aab should fail unless bundling #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabFlavor2Flavor4Debug" /*, "--stacktrace" */) + + and: + def buildResult = runner.buildAndFail() + + expect: + buildResult.task(":uploadDeployGateAabFlavor2Flavor4Debug").getOutcome() == TaskOutcome.FAILED + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + + @Unroll + def "flavor2Flavor4Debug apk require assembling #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -305,7 +469,51 @@ abstract class AcceptanceTestBaseSpec extends Specification { } @Unroll - def "customApk #agpVersion"() { + def "flavor2Flavor4Debug aab require bundling #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def assembleRunner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("bundleFlavor2Flavor4Debug" /*, "--stacktrace" */) + + def uploadRunner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabFlavor2Flavor4Debug" /*, "--stacktrace" */) + + and: + def assembleBuildResult = assembleRunner.build() + + and: + def uploadBuildResult = uploadRunner.build() + def result = wireMockRule.findRequestsMatching(postRequestedFor(urlPathEqualTo("/api/users/appOwner/apps")).build()) + def request = result.requests.first() + + expect: + assembleBuildResult.task(":bundleFlavor2Flavor4Debug").outcome == TaskOutcome.SUCCESS + uploadBuildResult.task(":uploadDeployGateAabFlavor2Flavor4Debug").outcome == TaskOutcome.SUCCESS + result.requests.size() == 1 + request.getPart("token").body.asString() == "api token" + request.getPart("file").body.present + request.getPart("message").body.asString() == "flavor2Flavor4Debug" + missingPart(request, "distribution_key") + missingPart(request, "release_note") + missingPart(request, "visibility") + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + + @Unroll + def "customApk apk #agpVersion"() { given: testAndroidProject.gradleProperties([ "agpVersion": agpVersion @@ -338,6 +546,40 @@ abstract class AcceptanceTestBaseSpec extends Specification { gradleVersion = agpEnv.gradleVersion as String } + @Unroll + def "customApk aab #agpVersion"() { + given: + testAndroidProject.gradleProperties([ + "agpVersion": agpVersion + ]) + + def runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath(testDeployGatePlugin.loadPluginClasspath()) + .withGradleVersion(gradleVersion) + .withArguments("uploadDeployGateAabCustomApk" /*, "--stacktrace" */) + + and: + def buildResult = runner.build() + def result = wireMockRule.findRequestsMatching(postRequestedFor(urlPathEqualTo("/api/users/appOwner/apps")).build()) + def request = result.requests.first() + + expect: + buildResult.task(":uploadDeployGateAabCustomApk").outcome == TaskOutcome.SUCCESS + result.requests.size() == 1 + request.getPart("token").body.asString() == "api token" + request.getPart("file").body.present + request.getPart("message").body.asString() == "custom message" + request.getPart("distribution_key").body.asString() == "custom distributionKey" + request.getPart("release_note").body.asString() == "custom releaseNote" + request.getPart("visibility").body.asString() == "custom visibility" + + where: + agpEnv << appBundleTestTargetAGPEnvs + agpVersion = agpEnv.agpVersion as String + gradleVersion = agpEnv.gradleVersion as String + } + private static boolean missingPart(LoggedRequest request, String name) { return request.parts.isEmpty() || !request.parts.any { it.name == name } } diff --git a/src/test/acceptance/com/deploygate/gradle/plugins/VersionString.groovy b/src/test/acceptance/com/deploygate/gradle/plugins/VersionString.groovy new file mode 100644 index 00000000..c5599bf7 --- /dev/null +++ b/src/test/acceptance/com/deploygate/gradle/plugins/VersionString.groovy @@ -0,0 +1,81 @@ +package com.deploygate.gradle.plugins + +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import javax.annotation.Nullable +import java.util.regex.Pattern + +class VersionString { + private static final Logger LOGGER = LoggerFactory.getLogger(this.getClass()) + private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)(?:\\.(\\d+))?\$") + + @Nullable + static VersionString tryParse(@Nullable String version) { + if (!version) { + return null + } + + LOGGER.info(version) + + def versions = version.split("-", 2) + + try { + def matcher = VERSION_PATTERN.matcher(versions[0]) + + if (!matcher.find() || matcher.groupCount() < 2) { + return null + } + + def major = matcher.group(1).toInteger() + def minor = matcher.group(2).toInteger() + def patch = 0 + + if (matcher.groupCount() >= 3) { + patch = matcher.group(3)?.toInteger() ?: 0 + } + + String addition = null + + if (versions.length == 2) { + addition = versions[1] + } + + new VersionString(major, minor, patch, addition) + } catch (NumberFormatException ignore) { + return null + } + } + + final int major + final int minor + final int patch + + @Nullable + final String addition + + VersionString(int major, int minor, int patch, @Nullable String addition) { + this.major = major + this.minor = minor + this.patch = patch + this.addition = addition + } + + @Override + String toString() { + def builder = new StringBuffer() + + builder.append(major) + builder.append(".") + builder.append(minor) + builder.append(".") + builder.append(patch) + + if (addition != null) { + builder.append("-") + builder.append(addition) + } + + return builder.toString() + } +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/ProcessorSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/ProcessorSpec.groovy index 3fe346ba..f2ef0ad1 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/ProcessorSpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/ProcessorSpec.groovy @@ -4,7 +4,7 @@ import com.deploygate.gradle.plugins.internal.agp.AndroidGradlePlugin import com.deploygate.gradle.plugins.internal.agp.IApplicationVariant import com.deploygate.gradle.plugins.tasks.factory.LoginTaskFactory import com.deploygate.gradle.plugins.tasks.factory.LogoutTaskFactory -import com.deploygate.gradle.plugins.tasks.factory.UploadApkTaskFactory +import com.deploygate.gradle.plugins.tasks.factory.UploadArtifactTaskFactory import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder import spock.lang.Specification @@ -24,10 +24,16 @@ class ProcessorSpec extends Specification { private LogoutTaskFactory logoutTaskFactory @Nonnull - private UploadApkTaskFactory applicationVariantBasedUploadApkTaskFactory + private UploadArtifactTaskFactory applicationVariantBasedUploadApkTaskFactory @Nonnull - private UploadApkTaskFactory stringBasedUploadApkTaskFactory + private UploadArtifactTaskFactory applicationVariantBasedUploadAabTaskFactory + + @Nonnull + private UploadArtifactTaskFactory stringBasedUploadApkTaskFactory + + @Nonnull + private UploadArtifactTaskFactory stringBasedUploadAabTaskFactory @Nonnull private Processor processor @@ -37,12 +43,14 @@ class ProcessorSpec extends Specification { loginTaskFactory = Mock() logoutTaskFactory = Mock() applicationVariantBasedUploadApkTaskFactory = Mock() + applicationVariantBasedUploadAabTaskFactory = Mock() stringBasedUploadApkTaskFactory = Mock() + stringBasedUploadAabTaskFactory = Mock() } def "addVariantOrCustomName should store given names except empty"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) when: processor.addVariantOrCustomName("") @@ -67,12 +75,14 @@ class ProcessorSpec extends Specification { 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } def "registerLoginTask should manipulate LoginTaskFactory"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) when: processor.registerLoginTask() @@ -84,12 +94,14 @@ class ProcessorSpec extends Specification { 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } def "registerLogoutTask should manipulate LogoutTaskFactory"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) when: processor.registerLogoutTask() @@ -101,47 +113,53 @@ class ProcessorSpec extends Specification { 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } def "registerDeclarationAwareUploadApkTask should manipulate String-based UploadApkTaskFactory"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) when: processor.registerDeclarationAwareUploadApkTask("dep1") then: - 1 * stringBasedUploadApkTaskFactory.registerUploadApkTask("dep1", LoginTaskFactory.TASK_NAME) + 1 * stringBasedUploadApkTaskFactory.registerUploadArtifactTask("dep1", LoginTaskFactory.TASK_NAME) and: 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } def "registerAggregatedDeclarationAwareUploadApkTask should collect upload tasks"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) when: processor.registerAggregatedDeclarationAwareUploadApkTask(["dep1", "dep2", "dep3"]) then: - 1 * stringBasedUploadApkTaskFactory.registerAggregatedUploadApkTask(["uploadDeployGateDep1", "uploadDeployGateDep2", "uploadDeployGateDep3"]) + 1 * stringBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask(["uploadDeployGateDep1", "uploadDeployGateDep2", "uploadDeployGateDep3"]) and: 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } @ConfineMetaClassChanges([AndroidGradlePlugin]) def "registerVariantAwareUploadApkTask should not do nothing unless AndroidGradlePlugin is applied"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) IApplicationVariant applicationVariant = Mock() and: @@ -156,13 +174,15 @@ class ProcessorSpec extends Specification { 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } @ConfineMetaClassChanges([AndroidGradlePlugin]) def "registerVariantAwareUploadApkTask should manipulate IApplicationVariant-based UploadApkTaskFactory if AndroidGradlePlugin is applied"() { given: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) IApplicationVariant applicationVariant = Mock() and: @@ -174,13 +194,15 @@ class ProcessorSpec extends Specification { processor.registerVariantAwareUploadApkTask(applicationVariant) then: - 1 * applicationVariantBasedUploadApkTaskFactory.registerUploadApkTask(applicationVariant, LoginTaskFactory.TASK_NAME) + 1 * applicationVariantBasedUploadApkTaskFactory.registerUploadArtifactTask(applicationVariant, LoginTaskFactory.TASK_NAME) and: 0 * loginTaskFactory._ 0 * logoutTaskFactory._ 0 * applicationVariantBasedUploadApkTaskFactory._ + 0 * applicationVariantBasedUploadAabTaskFactory._ 0 * stringBasedUploadApkTaskFactory._ + 0 * stringBasedUploadAabTaskFactory._ } def "just check getDependencyAncestorOfUploadTaskNames"() { @@ -195,7 +217,7 @@ class ProcessorSpec extends Specification { @Unroll def "canProcessVariantAware should depend on AndroidGradlePlugin.isApplied (#isAGPApplied)"() { setup: - processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, stringBasedUploadApkTaskFactory) + processor = new Processor(project, loginTaskFactory, logoutTaskFactory, applicationVariantBasedUploadApkTaskFactory, applicationVariantBasedUploadAabTaskFactory, stringBasedUploadApkTaskFactory, stringBasedUploadAabTaskFactory) and: AndroidGradlePlugin.metaClass.static.isApplied = { Project _ -> diff --git a/src/test/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactorySpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactorySpec.groovy index 2c8b1885..595e354c 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactorySpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/internal/gradle/TaskFactorySpec.groovy @@ -34,7 +34,7 @@ class TaskFactorySpec extends Specification { TaskFactory taskFactory = new TaskFactory(project) and: - def result = taskFactory.register(taskName, DefaultTask) + def result = taskFactory.registerOrFindBy(taskName, DefaultTask) expect: expectedTaskClass.isInstance(result) @@ -53,7 +53,7 @@ class TaskFactorySpec extends Specification { @ConfineMetaClassChanges([GradleCompat]) @Unroll - def "TaskFactory can handle duplicated tasks regardless of #gradleVersion"() { + def "TaskFactory#register does nothing if a task is duplicated regardless of #gradleVersion"() { given: Project project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() @@ -66,10 +66,41 @@ class TaskFactorySpec extends Specification { taskFactory.register(taskName, DefaultTask) and: - def result = taskFactory.register(taskName, DefaultTask, allowExisting) + def result = taskFactory.register(taskName, DefaultTask) expect: - !allowExisting && result == null || expectedTaskClass.isInstance(result) + result == null + + where: + taskName | gradleVersion | allowExisting + "agp300" | "4.1" | false + "agp310" | "4.4" | false + "agp320" | "4.6" | false + "border" | "4.7" | false + "border" | "4.8" | false + "agp330" | "4.10.1" | false + "agp340-beta04" | "5.1.1" | false + } + + @ConfineMetaClassChanges([GradleCompat]) + @Unroll + def "TaskFactory#registerOrFindBy return an existing task if duplicated regardless of #gradleVersion"() { + given: + Project project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + + GradleCompat.metaClass.static.getVersion = { -> + VersionString.tryParse(gradleVersion) + } + + and: + TaskFactory taskFactory = new TaskFactory(project) + taskFactory.register(taskName, DefaultTask) + + and: + def result = taskFactory.registerOrFindBy(taskName, DefaultTask) + + expect: + expectedTaskClass.isInstance(result) where: taskName | gradleVersion | allowExisting | expectedTaskClass @@ -80,12 +111,5 @@ class TaskFactorySpec extends Specification { "border" | "4.8" | true | SingleTask "agp330" | "4.10.1" | true | SingleTask "agp340-beta04" | "5.1.1" | true | SingleTask - "agp300" | "4.1" | false | null - "agp310" | "4.4" | false | null - "agp320" | "4.6" | false | null - "border" | "4.7" | false | null - "border" | "4.8" | false | null - "agp330" | "4.10.1" | false | null - "agp340-beta04" | "5.1.1" | false | null } } diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskConfigurationSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskConfigurationSpec.groovy new file mode 100644 index 00000000..8f794799 --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskConfigurationSpec.groovy @@ -0,0 +1,64 @@ +package com.deploygate.gradle.plugins.tasks + +import com.deploygate.gradle.plugins.artifacts.DirectAabInfo +import com.deploygate.gradle.plugins.dsl.Distribution +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import spock.lang.Specification +import spock.lang.Unroll + +class UploadAabTaskConfigurationSpec extends Specification { + + @Unroll + def "create a configuration"() { + setup: + def deployment = new NamedDeployment("dep1") + deployment.message = message + deployment.distribution { Distribution distribution -> + distribution.key = distributionKey + distribution.releaseNote = distributionReleaseNote + } + deployment.visibility = visibility + deployment.skipAssemble = skipAssemble + + and: + def aabInfo = new DirectAabInfo("dep1", null) + + and: + def configuration = UploadAabTask.createConfiguration(deployment, aabInfo) + + expect: + configuration.uploadParams.message == message + configuration.uploadParams.distributionKey == distributionKey + configuration.uploadParams.releaseNote == distributionReleaseNote + configuration.uploadParams.visibility == visibility + + where: + message | distributionKey | distributionReleaseNote | visibility | skipAssemble + null | null | null | null | false + "message" | "distributionKey" | "distributionReleaseNote" | "public" | true + } + + @Unroll + def "create a configuration for aab file handling"() { + setup: + def deployment = new NamedDeployment("dep1") + deployment.sourceFile = sourceFile + + and: + def aabInfo = new DirectAabInfo("dep1", aabFile) + + and: + def configuration = UploadAabTask.createConfiguration(deployment, aabInfo) + + expect: + configuration.artifactFile == sourceFile ?: aabFile + + where: + sourceFile | aabFile + null | null + null | new File("build.gradle") + new File("build.gradle") | null + new File("build.gradle") | new File("build.gradle") + } + +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskSpec.groovy new file mode 100644 index 00000000..7d4e9fe8 --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadAabTaskSpec.groovy @@ -0,0 +1,25 @@ +package com.deploygate.gradle.plugins.tasks + + +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import javax.annotation.Nonnull + +class UploadAabTaskSpec extends Specification { + + @Rule + TemporaryFolder testProjectDir = new TemporaryFolder() + + @Nonnull + private Project project + + def setup() { + project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + } + + // no specific assertions +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskConfigurationSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskConfigurationSpec.groovy index 8b83c009..611a39bb 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskConfigurationSpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskConfigurationSpec.groovy @@ -27,10 +27,10 @@ class UploadApkTaskConfigurationSpec extends Specification { def configuration = UploadApkTask.createConfiguration(deployment, apkInfo) expect: - configuration.message == message - configuration.distributionKey == distributionKey - configuration.releaseNote == distributionReleaseNote - configuration.visibility == visibility + configuration.uploadParams.message == message + configuration.uploadParams.distributionKey == distributionKey + configuration.uploadParams.releaseNote == distributionReleaseNote + configuration.uploadParams.visibility == visibility configuration.isSigningReady == signingReady configuration.isUniversalApk == universalApk @@ -53,7 +53,7 @@ class UploadApkTaskConfigurationSpec extends Specification { def configuration = UploadApkTask.createConfiguration(deployment, apkInfo) expect: - configuration.apkFile == sourceFile ?: apkFile + configuration.artifactFile == sourceFile ?: apkFile where: sourceFile | apkFile @@ -63,34 +63,4 @@ class UploadApkTaskConfigurationSpec extends Specification { new File("build.gradle") | new File("build.gradle") } - @Unroll - def "toUploadParams should not contain null values"() { - setup: - def configuration = new UploadApkTask.Configuration() - configuration.apkFile = apkFile - configuration.message = message - configuration.distributionKey = distributionKey - configuration.releaseNote = releaseNote - configuration.visibility = visibility - configuration.isSigningReady = isSigningReady - configuration.isUniversalApk = isUniversalApk - - and: - def params = configuration.toUploadParams() - - expect: - params["message"] == message - params["distribution_key"] == distributionKey - params["release_note"] == releaseNote - params["visibility"] == visibility - message != null || !params.containsKey("message") - distributionKey != null || !params.containsKey("distribution_key") - releaseNote != null || !params.containsKey("release_note") - visibility != null || !params.containsKey("visibility") - - where: - message | distributionKey | releaseNote | visibility | isSigningReady | isUniversalApk | apkFile - null | null | null | null | false | false | null - "message" | "distributionKey" | "releaseNote" | "public" | true | true | new File("build.gradle") - } } diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskSpec.groovy index 2090e86c..eabdfd7e 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskSpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadApkTaskSpec.groovy @@ -23,126 +23,7 @@ class UploadApkTaskSpec extends Specification { project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() } - def "getApiToken should get from an extension"() { - setup: - def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) - project.extensions.add("deploygate", deploygate) - - and: - def task = project.tasks.create("UploadApkTask", UploadApkTask) - - and: - deploygate.apiToken = null - - when: - task.apiToken - - then: - thrown(GradleException) - - when: - deploygate.apiToken = " " - - and: - task.apiToken - - then: - thrown(GradleException) - - when: - deploygate.apiToken = "token" - - and: - def token = task.apiToken - - then: - token == "token" - - when: - deploygate.apiToken = " token2 " - - and: - def token2 = task.apiToken - - then: - token2 == "token2" - } - - def "getAppOwnerName should get from an extension"() { - setup: - def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) - project.extensions.add("deploygate", deploygate) - - and: - def task = project.tasks.create("UploadApkTask", UploadApkTask) - - and: - deploygate.appOwnerName = null - - when: - task.appOwnerName - - then: - thrown(GradleException) - - when: - deploygate.appOwnerName = " " - - and: - task.appOwnerName - - then: - thrown(GradleException) - - when: - deploygate.appOwnerName = "appOwnerName" - - and: - def token = task.appOwnerName - - then: - token == "appOwnerName" - - when: - deploygate.appOwnerName = " appOwnerName2 " - - and: - def token2 = task.appOwnerName - - then: - token2 == "appOwnerName2" - } - - def "setVariantName cannot be called with different names"() { - setup: - def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) - project.extensions.add("deploygate", deploygate) - - and: - def task = project.tasks.create("UploadApkTask", UploadApkTask) - - when: - task.variantName = "dep1" - - then: - task.variantName == "dep1" - - when: "try to change the variant name" - task.variantName = "dep2" - - then: "but the change was ignored" - thrown(IllegalStateException) - task.variantName == "dep1" - - when: - task.variantName = "dep1" - - then: "no exception was thrown" - noExceptionThrown() - task.variantName == "dep1" - } - - def "uploadApkToServer should reject illegal states before processing"() { + def "doUpload should reject illegal states before processing"() { setup: def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) project.extensions.add("deploygate", deploygate) @@ -152,28 +33,10 @@ class UploadApkTaskSpec extends Specification { task.variantName = "dep1" when: "signing is required" - task.configuration = new UploadApkTask.Configuration(isSigningReady: false) - - and: - task.uploadApkToServer() - - then: - thrown(IllegalStateException) - - when: "apkFile is required" - task.configuration = new UploadApkTask.Configuration(apkFile: null, isSigningReady: true) - - and: - task.uploadApkToServer() - - then: - thrown(IllegalStateException) - - when: "apkFile must exist" - task.configuration = new UploadApkTask.Configuration(apkFile: new File("not found"), isSigningReady: true) + task.configuration = new UploadArtifactTask.Configuration(isSigningReady: false) and: - task.uploadApkToServer() + task.doUpload() then: thrown(IllegalStateException) diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskSpec.groovy new file mode 100644 index 00000000..823ebd4f --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskSpec.groovy @@ -0,0 +1,184 @@ +package com.deploygate.gradle.plugins.tasks + +import com.deploygate.gradle.plugins.dsl.DeployGateExtension +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import org.gradle.api.GradleException +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import javax.annotation.Nonnull + +class UploadArtifactTaskSpec extends Specification { + static class UploadArtifactTaskStub extends UploadArtifactTask { + + @Override + void applyTaskProfile() { + + } + + @Override + void runArtifactSpecificVerification() { + + } + } + + @Rule + TemporaryFolder testProjectDir = new TemporaryFolder() + + @Nonnull + private Project project + + def setup() { + project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + } + + def "getApiToken should get from an extension"() { + setup: + def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) + project.extensions.add("deploygate", deploygate) + + and: + def task = project.tasks.create("UploadArtifactTaskStub", UploadArtifactTaskStub) + + and: + deploygate.apiToken = null + + when: + task.apiToken + + then: + thrown(GradleException) + + when: + deploygate.apiToken = " " + + and: + task.apiToken + + then: + thrown(GradleException) + + when: + deploygate.apiToken = "token" + + and: + def token = task.apiToken + + then: + token == "token" + + when: + deploygate.apiToken = " token2 " + + and: + def token2 = task.apiToken + + then: + token2 == "token2" + } + + def "getAppOwnerName should get from an extension"() { + setup: + def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) + project.extensions.add("deploygate", deploygate) + + and: + def task = project.tasks.create("UploadArtifactTaskStub", UploadArtifactTaskStub) + + and: + deploygate.appOwnerName = null + + when: + task.appOwnerName + + then: + thrown(GradleException) + + when: + deploygate.appOwnerName = " " + + and: + task.appOwnerName + + then: + thrown(GradleException) + + when: + deploygate.appOwnerName = "appOwnerName" + + and: + def token = task.appOwnerName + + then: + token == "appOwnerName" + + when: + deploygate.appOwnerName = " appOwnerName2 " + + and: + def token2 = task.appOwnerName + + then: + token2 == "appOwnerName2" + } + + def "setVariantName cannot be called with different names"() { + setup: + def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) + project.extensions.add("deploygate", deploygate) + + and: + def task = project.tasks.create("UploadArtifactTaskStub", UploadArtifactTaskStub) + + when: + task.variantName = "dep1" + + then: + task.variantName == "dep1" + + when: "try to change the variant name" + task.variantName = "dep2" + + then: "but the change was ignored" + thrown(IllegalStateException) + task.variantName == "dep1" + + when: + task.variantName = "dep1" + + then: "no exception was thrown" + noExceptionThrown() + task.variantName == "dep1" + } + + def "doUpload should reject illegal states before processing"() { + setup: + def deploygate = new DeployGateExtension(project, project.container(NamedDeployment)) + project.extensions.add("deploygate", deploygate) + + and: + def task = project.tasks.create("UploadArtifactTaskStub", UploadArtifactTaskStub) + task.variantName = "dep1" + + when: "apkFile is required" + task.configuration = new UploadArtifactTask.Configuration(artifactFile: null, isSigningReady: true) + + and: + task.doUpload() + + then: + thrown(IllegalStateException) + + when: "apkFile must exist" + task.configuration = new UploadArtifactTask.Configuration(artifactFile: new File("not found"), isSigningReady: true) + + and: + task.doUpload() + + then: + thrown(IllegalStateException) + } +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskUploadParamsSpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskUploadParamsSpec.groovy new file mode 100644 index 00000000..fb00502d --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/UploadArtifactTaskUploadParamsSpec.groovy @@ -0,0 +1,35 @@ +package com.deploygate.gradle.plugins.tasks + +import spock.lang.Specification +import spock.lang.Unroll + +class UploadArtifactTaskUploadParamsSpec extends Specification { + + @Unroll + def "toMap should not contain null values"() { + setup: + def uploadParams = new UploadArtifactTask.UploadParams() + uploadParams.message = message + uploadParams.distributionKey = distributionKey + uploadParams.releaseNote = releaseNote + uploadParams.visibility = visibility + + and: + def params = uploadParams.toMap() + + expect: + params["message"] == message + params["distribution_key"] == distributionKey + params["release_note"] == releaseNote + params["visibility"] == visibility + message != null || !params.containsKey("message") + distributionKey != null || !params.containsKey("distribution_key") + releaseNote != null || !params.containsKey("release_note") + visibility != null || !params.containsKey("visibility") + + where: + message | distributionKey | releaseNote | visibility | isSigningReady | isUniversalApk | apkFile + null | null | null | null | false | false | null + "message" | "distributionKey" | "releaseNote" | "public" | true | true | new File("build.gradle") + } +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactorySpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactorySpec.groovy new file mode 100644 index 00000000..ce3485de --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadAabTaskFactorySpec.groovy @@ -0,0 +1,111 @@ +package com.deploygate.gradle.plugins.tasks.factory + +import com.deploygate.gradle.plugins.artifacts.DirectAabInfo +import com.deploygate.gradle.plugins.artifacts.DirectApkInfo +import com.deploygate.gradle.plugins.artifacts.PackageAppTaskCompat +import com.deploygate.gradle.plugins.dsl.DeployGateExtension +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.internal.agp.IApplicationVariant +import com.deploygate.gradle.plugins.internal.gradle.GradleCompat +import com.deploygate.gradle.plugins.internal.gradle.LazyConfigurableTask +import com.deploygate.gradle.plugins.tasks.UploadAabTask +import com.deploygate.gradle.plugins.tasks.UploadApkTask +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import spock.lang.Specification +import spock.util.mop.ConfineMetaClassChanges + +import javax.annotation.Nonnull + +class AGPBasedUploadAabTaskFactorySpec extends Specification { + @Nonnull + private Project project + + @Nonnull + private NamedDomainObjectContainer deployments + + @Nonnull + private AGPBasedUploadAabTaskFactory agpBasedUploadAabTaskFactory + + def setup() { + project = ProjectBuilder.builder().build() + GradleCompat.init(project) + deployments = project.container(NamedDeployment) + + project.extensions.add("deploygate", new DeployGateExtension(project, deployments)) + } + + def "registerAggregatedUploadApkTask should not be supported"() { + given: + agpBasedUploadAabTaskFactory = new AGPBasedUploadAabTaskFactory(project) + + when: + agpBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask() + + then: + thrown(IllegalAccessException) + } + + @ConfineMetaClassChanges([PackageAppTaskCompat]) + def "registerUploadArtifactTask should add a UploadAabTask"() { + setup: + def variantName = "dep1" + def variant = Mock(IApplicationVariant) + variant.name >> variantName + variant.lazyPackageApplication() >> Stub(LazyConfigurableTask, name: variantName) + + and: + agpBasedUploadAabTaskFactory = new AGPBasedUploadAabTaskFactory(project) + + and: + PackageAppTaskCompat.metaClass.static.getAabInfo = { LazyConfigurableTask _ -> + new DirectAabInfo(variantName, null) + } + + when: + agpBasedUploadAabTaskFactory.registerUploadArtifactTask(variant) + + and: + def task = project.tasks.findByName("uploadDeployGateAabDep1") + + then: + task + task instanceof UploadAabTask + } + + @ConfineMetaClassChanges([PackageAppTaskCompat]) + def "registerUploadArtifactTask should modify the existing instance if already exist"() { + given: + def variantName = "dep1" + def variant = Mock(IApplicationVariant) + variant.name >> variantName + variant.lazyPackageApplication() >> Stub(LazyConfigurableTask, name: variantName) + + and: + agpBasedUploadAabTaskFactory = new AGPBasedUploadAabTaskFactory(project) + + and: + PackageAppTaskCompat.metaClass.static.getAabInfo = { LazyConfigurableTask _ -> + new DirectAabInfo(variantName, null) + } + + when: + agpBasedUploadAabTaskFactory.registerUploadArtifactTask(variant) + + and: + def firstTask = project.tasks.findByName("uploadDeployGateAabDep1") + + then: + firstTask + + when: + agpBasedUploadAabTaskFactory.registerUploadArtifactTask(variant) + + and: + def secondTask = project.tasks.findByName("uploadDeployGateAabDep1") + + then: + firstTask == secondTask + } +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactorySpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactorySpec.groovy index b8c64fd7..65509050 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactorySpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/AGPBasedUploadApkTaskFactorySpec.groovy @@ -39,14 +39,14 @@ class AGPBasedUploadApkTaskFactorySpec extends Specification { agpBasedUploadApkTaskFactory = new AGPBasedUploadApkTaskFactory(project) when: - agpBasedUploadApkTaskFactory.registerAggregatedUploadApkTask() + agpBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask() then: thrown(IllegalAccessException) } @ConfineMetaClassChanges([PackageAppTaskCompat]) - def "registerUploadApkTask should add a UploadApkTask"() { + def "registerUploadArtifactTask should add a UploadApkTask"() { setup: def variantName = "dep1" def variant = Mock(IApplicationVariant) @@ -62,7 +62,7 @@ class AGPBasedUploadApkTaskFactorySpec extends Specification { } when: - agpBasedUploadApkTaskFactory.registerUploadApkTask(variant) + agpBasedUploadApkTaskFactory.registerUploadArtifactTask(variant) and: def task = project.tasks.findByName("uploadDeployGateDep1") @@ -73,7 +73,7 @@ class AGPBasedUploadApkTaskFactorySpec extends Specification { } @ConfineMetaClassChanges([PackageAppTaskCompat]) - def "registerUploadApkTask should modify the existing instance if already exist"() { + def "registerUploadArtifactTask should modify the existing instance if already exist"() { given: def variantName = "dep1" def variant = Mock(IApplicationVariant) @@ -89,7 +89,7 @@ class AGPBasedUploadApkTaskFactorySpec extends Specification { } when: - agpBasedUploadApkTaskFactory.registerUploadApkTask(variant) + agpBasedUploadApkTaskFactory.registerUploadArtifactTask(variant) and: def firstTask = project.tasks.findByName("uploadDeployGateDep1") @@ -98,7 +98,7 @@ class AGPBasedUploadApkTaskFactorySpec extends Specification { firstTask when: - agpBasedUploadApkTaskFactory.registerUploadApkTask(variant) + agpBasedUploadApkTaskFactory.registerUploadArtifactTask(variant) and: def secondTask = project.tasks.findByName("uploadDeployGateDep1") diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactorySpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactorySpec.groovy new file mode 100644 index 00000000..593c8f01 --- /dev/null +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadAabTaskFactorySpec.groovy @@ -0,0 +1,155 @@ +package com.deploygate.gradle.plugins.tasks.factory + +import com.deploygate.gradle.plugins.dsl.DeployGateExtension +import com.deploygate.gradle.plugins.dsl.NamedDeployment +import com.deploygate.gradle.plugins.internal.gradle.GradleCompat +import com.deploygate.gradle.plugins.tasks.UploadAabTask +import org.gradle.api.GradleException +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + +import javax.annotation.Nonnull + +class DSLBasedUploadAabTaskFactorySpec extends Specification { + + @Rule + TemporaryFolder testProjectDir = new TemporaryFolder() + + @Nonnull + private Project project + + @Nonnull + private DSLBasedUploadAabTaskFactory dslBasedUploadAabTaskFactory + + def setup() { + project = ProjectBuilder.builder().withProjectDir(testProjectDir.root).build() + GradleCompat.init(project) + } + + def "registerAggregatedUploadArtifactTask should not add any task if empty is given"() { + given: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + def taskNames = project.tasks.toList().collect { it.name } + + when: + dslBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask() + + then: + taskNames == project.tasks.toList().collect { it.name } + + when: + dslBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask([]) + + then: + taskNames == project.tasks.toList().collect { it.name } + } + + def "registerAggregatedUploadArtifactTask should add a task which run given tasks only once"() { + given: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + + when: + dslBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask("task1", "task2") + + and: + def task = project.tasks.findByName("uploadDeployGateAab") + + then: + task.dependsOn.flatten().collect { + if (it.hasProperty("taskName")) { + it.taskName + } else if (it.hasProperty("name")) { + it.name + } else { + it + } + } == ["task1", "task2"] + } + + def "registerAggregatedUploadArtifactTask should modify the existing itself if called twice"() { + given: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + + when: + dslBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask("task1", "task2") + dslBasedUploadAabTaskFactory.registerAggregatedUploadArtifactTask("task3", "task4") + + and: + def task = project.tasks.findByName("uploadDeployGateAab") + + then: + task.dependsOn.flatten().collect { + if (it.hasProperty("taskName")) { + it.taskName + } else if (it.hasProperty("name")) { + it.name + } else { + it + } + } == ["task1", "task2", "task3", "task4"] + } + + def "registerAggregatedUploadArtifactTask should add a UploadAabTask"() { + given: + NamedDomainObjectContainer deployments = project.container(NamedDeployment) + deployments.create("dep1") + project.extensions.add("deploygate", new DeployGateExtension(project, deployments)) + + and: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + + when: + dslBasedUploadAabTaskFactory.registerUploadArtifactTask("dep1") + + and: + def task = project.tasks.findByName("uploadDeployGateAabDep1") + + then: + task + task instanceof UploadAabTask + task.group == DeployGateTaskFactory.GROUP_NAME + } + + def "registerAggregatedUploadArtifactTask should not override itself if already exist"() { + given: + NamedDomainObjectContainer deployments = project.container(NamedDeployment) + deployments.create("dep1") + project.extensions.add("deploygate", new DeployGateExtension(project, deployments)) + + and: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + + and: + project.tasks.create("uploadDeployGateAabDep1") + + when: + dslBasedUploadAabTaskFactory.registerUploadArtifactTask("dep1") + + and: + def task = project.tasks.findByName("uploadDeployGateAabDep1") + + then: + task + !(task instanceof UploadAabTask) + } + + def "registerAggregatedUploadArtifactTask should not allow adding names which do not exist in build.gradle"() { + given: + NamedDomainObjectContainer deployments = project.container(NamedDeployment) + deployments.create("dep1") + project.extensions.add("deploygate", new DeployGateExtension(project, deployments)) + + and: + dslBasedUploadAabTaskFactory = new DSLBasedUploadAabTaskFactory(project) + + when: + dslBasedUploadAabTaskFactory.registerUploadArtifactTask("dep2") + + then: + thrown(GradleException) + } +} diff --git a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactorySpec.groovy b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactorySpec.groovy index 8827d9af..271139b1 100644 --- a/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactorySpec.groovy +++ b/src/test/groovy/com/deploygate/gradle/plugins/tasks/factory/DSLBasedUploadApkTaskFactorySpec.groovy @@ -30,30 +30,30 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { GradleCompat.init(project) } - def "registerAggregatedUploadApkTask should not add any task if empty is given"() { + def "registerAggregatedUploadArtifactTask should not add any task if empty is given"() { given: dslBasedUploadApkTaskFactory = new DSLBasedUploadApkTaskFactory(project) def taskNames = project.tasks.toList().collect { it.name } when: - dslBasedUploadApkTaskFactory.registerAggregatedUploadApkTask() + dslBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask() then: taskNames == project.tasks.toList().collect { it.name } when: - dslBasedUploadApkTaskFactory.registerAggregatedUploadApkTask([]) + dslBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask([]) then: taskNames == project.tasks.toList().collect { it.name } } - def "registerAggregatedUploadApkTask should add a task which run given tasks only once"() { + def "registerAggregatedUploadArtifactTask should add a task which run given tasks only once"() { given: dslBasedUploadApkTaskFactory = new DSLBasedUploadApkTaskFactory(project) when: - dslBasedUploadApkTaskFactory.registerAggregatedUploadApkTask("task1", "task2") + dslBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask("task1", "task2") and: def task = project.tasks.findByName("uploadDeployGate") @@ -70,13 +70,13 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { } == ["task1", "task2"] } - def "registerAggregatedUploadApkTask should modify the existing itself if called twice"() { + def "registerAggregatedUploadArtifactTask should modify the existing itself if called twice"() { given: dslBasedUploadApkTaskFactory = new DSLBasedUploadApkTaskFactory(project) when: - dslBasedUploadApkTaskFactory.registerAggregatedUploadApkTask("task1", "task2") - dslBasedUploadApkTaskFactory.registerAggregatedUploadApkTask("task3", "task4") + dslBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask("task1", "task2") + dslBasedUploadApkTaskFactory.registerAggregatedUploadArtifactTask("task3", "task4") and: def task = project.tasks.findByName("uploadDeployGate") @@ -93,7 +93,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { } == ["task1", "task2", "task3", "task4"] } - def "registerUploadApkTask should add a UploadApkTask"() { + def "registerUploadArtifactTask should add a UploadApkTask"() { given: NamedDomainObjectContainer deployments = project.container(NamedDeployment) deployments.create("dep1") @@ -103,7 +103,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { dslBasedUploadApkTaskFactory = new DSLBasedUploadApkTaskFactory(project) when: - dslBasedUploadApkTaskFactory.registerUploadApkTask("dep1") + dslBasedUploadApkTaskFactory.registerUploadArtifactTask("dep1") and: def task = project.tasks.findByName("uploadDeployGateDep1") @@ -114,7 +114,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { task.group == DeployGateTaskFactory.GROUP_NAME } - def "registerUploadApkTask should not override itself if already exist"() { + def "registerUploadArtifactTask should not override itself if already exist"() { given: NamedDomainObjectContainer deployments = project.container(NamedDeployment) deployments.create("dep1") @@ -127,7 +127,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { project.tasks.create("uploadDeployGateDep1") when: - dslBasedUploadApkTaskFactory.registerUploadApkTask("dep1") + dslBasedUploadApkTaskFactory.registerUploadArtifactTask("dep1") and: def task = project.tasks.findByName("uploadDeployGateDep1") @@ -137,7 +137,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { !(task instanceof UploadApkTask) } - def "registerUploadApkTask should not allow adding names which do not exist in build.gradle"() { + def "registerUploadArtifactTask should not allow adding names which do not exist in build.gradle"() { given: NamedDomainObjectContainer deployments = project.container(NamedDeployment) deployments.create("dep1") @@ -147,7 +147,7 @@ class DSLBasedUploadApkTaskFactorySpec extends Specification { dslBasedUploadApkTaskFactory = new DSLBasedUploadApkTaskFactory(project) when: - dslBasedUploadApkTaskFactory.registerUploadApkTask("dep2") + dslBasedUploadApkTaskFactory.registerUploadArtifactTask("dep2") then: thrown(GradleException)