<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013-2014 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package de.felixschulze.gradle

import com.android.build.gradle.api.ApplicationVariant
import de.felixschulze.gradle.util.ProgressHttpEntityWrapper
import de.felixschulze.teamcity.TeamCityProgressType
import de.felixschulze.teamcity.TeamCityStatusMessageHelper
import groovy.json.JsonSlurper
import org.apache.commons.io.FilenameUtils
import org.apache.http.HttpHost
import org.apache.http.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.apache.http.entity.mime.content.FileBody
import org.apache.http.entity.mime.content.StringBody
import org.apache.http.impl.client.HttpClientBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.Nullable
import org.gradle.api.logging.Logger
import org.gradle.api.tasks.TaskAction
import org.gradle.logging.ProgressLogger
import org.gradle.logging.ProgressLoggerFactory

import java.util.regex.Pattern

class HockeyAppUploadTask extends DefaultTask {

    File applicationFile
    File symbolsDirectory
    File mappingFile
    String variantName
    ApplicationVariant applicationVariant
    boolean mightHaveMapping = true   // Specify otherwise in Android config


    HockeyAppUploadTask() {
        super()
        this.description = "Uploads the app (Android: (.apk, mapping.txt), iOS:(.ipa, .dsym)) to HockeyApp"
    }


    @TaskAction
    def upload() throws IOException {


        // Get the first output apk file
        applicationVariant.outputs.each {
            if (FilenameUtils.isExtension(it.outputFile.getName(),"apk")) {
                applicationFile = it.outputFile
                return true
            }
        }

        if (applicationVariant.getObfuscation()) {
            mappingFile = applicationVariant.getMappingFile()
        } else {
            mightHaveMapping = false
        }

        if (!getApiToken()) {
            throw new IllegalArgumentException("Cannot upload to HockeyApp because API Token is missing")
        }

        if (!applicationFile?.exists()) {
            if (!project.hockeyapp.appFileNameRegex) {
                throw new IllegalArgumentException("No applicationFile found or no appFileNameRegex provided.")
            }
            if (!project.hockeyapp.outputDirectory || !project.hockeyapp.outputDirectory.exists()) {
                throw new IllegalArgumentException("The outputDirectory (" + project.hockeyapp.outputDirectory ? project.hockeyapp.outputDirectory.absolutePath : " not defined " + ") doesn't exists")
            }
            applicationFile = getFile(project.hockeyapp.appFileNameRegex, project.hockeyapp.outputDirectory);
            if (!applicationFile) {
                throw new IllegalStateException("No app file found in directory " + project.hockeyapp.outputDirectory.absolutePath)
            }
        }

        logger.lifecycle("App file: " + applicationFile.absolutePath)

        // Retrieve mapping file if not using Android Gradle Plugin
        // Requires it to be set in the project config
        if (mightHaveMapping && !mappingFile && project.hockeyapp.symbolsDirectory?.exists()) {
            symbolsDirectory = project.hockeyapp.symbolsDirectory
            mappingFile = getFile(project.hockeyapp.mappingFileNameRegex, symbolsDirectory);

            if (!mappingFile) {
                logger.warn("No Mapping file found.")
            }
        }

        if (mappingFile?.exists()) {
            logger.lifecycle("Mapping file: " + mappingFile.absolutePath)
        }

        String appId = null
        if (project.hockeyapp.variantToApplicationId) {
            appId = project.hockeyapp.variantToApplicationId[variantName]
            if (!appId)
                throw new IllegalArgumentException("Could not resolve app ID for variant: ${variantName} in the variantToApplicationId map.")
        }

        uploadApp(applicationFile, mappingFile, appId)
    }

    def void uploadApp(File appFile, @Nullable File mappingFile, String appId) {

        ProgressLogger progressLogger = services.get(ProgressLoggerFactory).newOperation(this.getClass())
        progressLogger.start("Upload file to Hockey App", "Upload file")
        if (project.hockeyapp.teamCityLog) {
            println TeamCityStatusMessageHelper.buildProgressString(TeamCityProgressType.START, "Upload file to Hockey App")
        }

        RequestConfig.Builder requestBuilder = RequestConfig.custom()
        requestBuilder = requestBuilder.setConnectTimeout(project.hockeyapp.timeout)
        requestBuilder = requestBuilder.setConnectionRequestTimeout(project.hockeyapp.timeout)

        String proxyHost = System.getProperty("http.proxyHost", "")
        int proxyPort = System.getProperty("http.proxyPort", "0") as int
        if (proxyHost.length() > 0 && proxyPort > 0) {
            logger.lifecycle("Using proxy: " + proxyHost + ":" + proxyPort)
            HttpHost proxy = new HttpHost(proxyHost, proxyPort);
            requestBuilder = requestBuilder.setProxy(proxy)
        }

        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setDefaultRequestConfig(requestBuilder.build());
        HttpClient httpClient = builder.build();

        String uploadUrl = "https://rink.hockeyapp.net/api/2/apps"
        if (appId) {
            uploadUrl = "https://rink.hockeyapp.net/api/2/apps/${appId}/app_versions/upload"
        }

        HttpPost httpPost = new HttpPost(uploadUrl)
        logger.info("Will upload to: ${uploadUrl}")

        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create()

        entityBuilder.addPart("ipa", new FileBody(appFile))
        if (mappingFile?.exists()) {
            entityBuilder.addPart("dsym", new FileBody(mappingFile))
        }
        decorateWithOptionalProperties(entityBuilder)

        httpPost.addHeader("X-HockeyAppToken", getApiToken())


        int lastProgress = 0
        Logger loggerForCallback = logger
        Boolean teamCityLog = project.hockeyapp.teamCityLog
        ProgressHttpEntityWrapper.ProgressCallback progressCallback = new ProgressHttpEntityWrapper.ProgressCallback() {

            @Override
            public void progress(float progress) {
                int progressInt = (int)progress
                if (progressInt > lastProgress) {
                    lastProgress = progressInt
                    if (progressInt % 5 == 0) {
                        progressLogger.progress(progressInt + "% uploaded")
                        loggerForCallback.info(progressInt + "% uploaded")
                        if (teamCityLog) {
                            println TeamCityStatusMessageHelper.buildProgressString(TeamCityProgressType.MESSAGE, progressInt + "% uploaded")
                        }
                    }
                }
            }

        }

        httpPost.setEntity(new ProgressHttpEntityWrapper(entityBuilder.build(), progressCallback));

        logger.info("Request: " + httpPost.getRequestLine().toString())

        HttpResponse response = httpClient.execute(httpPost)

        if (response.getStatusLine().getStatusCode() != 201) {
            if (response.getEntity() && response.getEntity().getContentLength() > 0) {
                InputStreamReader reader = new InputStreamReader(response.getEntity().content)
                def uploadResponse = new JsonSlurper().parse(reader)<commit_msg>Groovy syntac<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013-2014 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package de.felixschulze.gradle

import com.android.build.gradle.api.ApplicationVariant
import de.felixschulze.gradle.util.ProgressHttpEntityWrapper
import de.felixschulze.teamcity.TeamCityProgressType
import de.felixschulze.teamcity.TeamCityStatusMessageHelper
import groovy.json.JsonSlurper
import org.apache.commons.io.FilenameUtils
import org.apache.http.HttpHost
import org.apache.http.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.apache.http.entity.mime.content.FileBody
import org.apache.http.entity.mime.content.StringBody
import org.apache.http.impl.client.HttpClientBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.Nullable
import org.gradle.api.logging.Logger
import org.gradle.api.tasks.TaskAction
import org.gradle.logging.ProgressLogger
import org.gradle.logging.ProgressLoggerFactory

import java.util.regex.Pattern

class HockeyAppUploadTask extends DefaultTask {

    File applicationFile
    File symbolsDirectory
    File mappingFile
    String variantName
    ApplicationVariant applicationVariant
    boolean mightHaveMapping = true   // Specify otherwise in Android config


    HockeyAppUploadTask() {
        super()
        this.description = "Uploads the app (Android: (.apk, mapping.txt), iOS:(.ipa, .dsym)) to HockeyApp"
    }


    @TaskAction
    def upload() throws IOException {


        // Get the first output apk file
        applicationVariant.outputs.each {
            if (FilenameUtils.isExtension(it.outputFile.getName(),"apk")) {
                applicationFile = it.outputFile
                return true
            }
        }

        if (applicationVariant.getObfuscation()) {
            mappingFile = applicationVariant.getMappingFile()
        } else {
            mightHaveMapping = false
        }

        if (!getApiToken()) {
            throw new IllegalArgumentException("Cannot upload to HockeyApp because API Token is missing")
        }

        if (!applicationFile?.exists()) {
            if (!project.hockeyapp.appFileNameRegex) {
                throw new IllegalArgumentException("No applicationFile found or no appFileNameRegex provided.")
            }
            if (!project.hockeyapp.outputDirectory || !project.hockeyapp.outputDirectory.exists()) {
                throw new IllegalArgumentException("The outputDirectory (" + project.hockeyapp.outputDirectory ? project.hockeyapp.outputDirectory.absolutePath : " not defined " + ") doesn't exists")
            }
            applicationFile = getFile(project.hockeyapp.appFileNameRegex, project.hockeyapp.outputDirectory);
            if (!applicationFile) {
                throw new IllegalStateException("No app file found in directory " + project.hockeyapp.outputDirectory.absolutePath)
            }
        }

        logger.lifecycle("App file: " + applicationFile.absolutePath)

        // Retrieve mapping file if not using Android Gradle Plugin
        // Requires it to be set in the project config
        if (mightHaveMapping && !mappingFile && project.hockeyapp.symbolsDirectory?.exists()) {
            symbolsDirectory = project.hockeyapp.symbolsDirectory
            mappingFile = getFile(project.hockeyapp.mappingFileNameRegex, symbolsDirectory);

            if (!mappingFile) {
                logger.warn("No Mapping file found.")
            }
        }

        if (mappingFile?.exists()) {
            logger.lifecycle("Mapping file: " + mappingFile.absolutePath)
        }

        String appId = null
        if (project.hockeyapp.variantToApplicationId) {
            appId = project.hockeyapp.variantToApplicationId[variantName]
            if (!appId)
                throw new IllegalArgumentException("Could not resolve app ID for variant: ${variantName} in the variantToApplicationId map.")
        }

        uploadApp(applicationFile, mappingFile, appId)
    }

    def void uploadApp(File appFile, @Nullable File mappingFile, String appId) {

        ProgressLogger progressLogger = services.get(ProgressLoggerFactory).newOperation(this.getClass())
        progressLogger.start("Upload file to Hockey App", "Upload file")
        if (project.hockeyapp.teamCityLog) {
            println TeamCityStatusMessageHelper.buildProgressString(TeamCityProgressType.START, "Upload file to Hockey App")
        }

        RequestConfig.Builder requestBuilder = RequestConfig.custom()
        requestBuilder = requestBuilder.setConnectTimeout(project.hockeyapp.timeout)
        requestBuilder = requestBuilder.setConnectionRequestTimeout(project.hockeyapp.timeout)

        String proxyHost = System.getProperty("http.proxyHost", "")
        int proxyPort = System.getProperty("http.proxyPort", "0") as int
        if (proxyHost.length() > 0 && proxyPort > 0) {
            logger.lifecycle("Using proxy: " + proxyHost + ":" + proxyPort)
            HttpHost proxy = new HttpHost(proxyHost, proxyPort);
            requestBuilder = requestBuilder.setProxy(proxy)
        }

        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setDefaultRequestConfig(requestBuilder.build());
        HttpClient httpClient = builder.build();

        String uploadUrl = "https://rink.hockeyapp.net/api/2/apps"
        if (appId) {
            uploadUrl = "https://rink.hockeyapp.net/api/2/apps/${appId}/app_versions/upload"
        }

        HttpPost httpPost = new HttpPost(uploadUrl)
        logger.info("Will upload to: ${uploadUrl}")

        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create()

        entityBuilder.addPart("ipa", new FileBody(appFile))
        if (mappingFile?.exists()) {
            entityBuilder.addPart("dsym", new FileBody(mappingFile))
        }
        decorateWithOptionalProperties(entityBuilder)

        httpPost.addHeader("X-HockeyAppToken", getApiToken())


        int lastProgress = 0
        Logger loggerForCallback = logger
        Boolean teamCityLog = project.hockeyapp.teamCityLog
        ProgressHttpEntityWrapper.ProgressCallback progressCallback = new ProgressHttpEntityWrapper.ProgressCallback() {

            @Override
            public void progress(float progress) {
                int progressInt = (int)progress
                if (progressInt > lastProgress) {
                    lastProgress = progressInt
                    if (progressInt % 5 == 0) {
                        progressLogger.progress(progressInt + "% uploaded")
                        loggerForCallback.info(progressInt + "% uploaded")
                        if (teamCityLog) {
                            println TeamCityStatusMessageHelper.buildProgressString(TeamCityProgressType.MESSAGE, progressInt + "% uploaded")
                        }
                    }
                }
            }

        }

        httpPost.setEntity(new ProgressHttpEntityWrapper(entityBuilder.build(), progressCallback));

        logger.info("Request: " + httpPost.getRequestLine().toString())

        HttpResponse response = httpClient.execute(httpPost)

        if (response.getStatusLine().getStatusCode() != 201) {
            if (response.getEntity()?.getContentLength() > 0) {
                InputStreamReader reader = new InputStreamReader(response.getEntity().content)
                def uploadResponse = new JsonSlurper().parse(reader)
{'fraction_non_alphanumeric': 0.08542742731124137, 'fraction_numerical': 0.0023213974812837327, 'mean_word_length': 2.8749718911625814, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '374800', 'n_tokens_mistral': 4357, 'n_tokens_neox': 4149, 'n_words': 1111}