'use strict' ; import fs = require ( 'fs' ) ; import os = require ( 'os' ) ; import path = require ( 'path' ) ; import tl = require ( 'azure-pipelines-task-lib/task' ) ; import { ToolRunner } from 'azure-pipelines-task-lib/toolrunner' ; export class UserCredentials { username : string ; password : string ; appSpecificPassword : string ; fastlaneSession : string ; public UserCredentials ( ) { } } /**
 * Information for the App Store Connect API key used by fastlane
 * See https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file
 */ export interface ApiKey { /**
     * Key ID (for example 'D383SF740')
     */ key_id : string ; /**
     * Issuer ID (for example '6053b7fe-68a8-4acb-89be-165aa6465141')
     */ issuer_id : string ; /**
     * The base64-encoded private key contents of the p8 file from Apple.
     */ key : string ; /**
     * Optional, set to true to use Enterprise account
     */ in_house ? : boolean ; /**
     * Indicates whether the key content is base64 encoded
     */ is_key_content_base64 : boolean ; } async function run ( ) { const appSpecificPasswordEnvVar = 'FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD' ; const fastlaneSessionEnvVar = 'FASTLANE_SESSION' ; let apiKeyFilePath ; let isTwoFactorAuthEnabled = false ; let isUsingApiKey = false ; try { tl . setResourcePath ( path . join ( __dirname , 'task.json' ) ) ; if ( os . platform ( ) !== 'darwin' ) { throw new Error ( tl . loc ( 'DarwinOnly' ) ) ; } tl . debug ( 'Reading all inputs...' ) ; let authType = tl . getInput ( 'authType' , false ) ; let credentials = new UserCredentials ( ) ; let apiKey ; const createapiKeyFilePath = ( apiKeyId ) => { const tempPath = tl . getVariable ( 'Agent.TempDirectory' ) || tl . getVariable ( 'Agent.BuildDirectory' ) ; return path . join ( tempPath , `api_key${ apiKeyId }.json` ) ; } ; if ( authType === 'ServiceEndpoint' ) { let serviceEndpoint = tl . getEndpointAuthorization ( tl . getInput ( 'serviceEndpoint' , true ) , false ) ; if ( serviceEndpoint . scheme === 'Token' ) { isUsingApiKey = true ; apiKeyFilePath = createapiKeyFilePath ( serviceEndpoint . parameters [ 'apiKeyId' ] ) ; apiKey = { key_id : serviceEndpoint . parameters [ 'apiKeyId' ] , issuer_id : serviceEndpoint . parameters [ 'apiKeyIssuerId' ] , key : serviceEndpoint . parameters [ 'apitoken' ] , in_house : serviceEndpoint . parameters [ 'apiKeyInHouse' ] === 'apiKeyInHouse_true' , is_key_content_base64 : true } ; } else { credentials . username = serviceEndpoint . parameters [ 'username' ] ; credentials . password = serviceEndpoint . parameters [ 'password' ] ; credentials . appSpecificPassword = serviceEndpoint . parameters [ 'appSpecificPassword' ] ; if ( credentials . appSpecificPassword ) { isTwoFactorAuthEnabled = true ; let fastlaneSession = serviceEndpoint . parameters [ 'fastlaneSession' ] ; if ( ! fastlaneSession ) { throw Error ( tl . loc ( 'FastlaneSessionEmpty' ) ) ; } credentials . fastlaneSession = fastlaneSession ; } } } else if ( authType === 'UserAndPass' ) { credentials . username = tl . getInput ( 'username' , true ) ; credentials . password = tl . getInput ( 'password' , true ) ; isTwoFactorAuthEnabled = tl . getBoolInput ( 'isTwoFactorAuth' ) ; if ( isTwoFactorAuthEnabled ) { credentials . appSpecificPassword = tl . getInput ( 'appSpecificPassword' , true ) ; credentials . fastlaneSession = tl . getInput ( 'fastlaneSession' , true ) ; } } else if ( authType === 'ApiKey' ) { isUsingApiKey = true ; apiKeyFilePath = createapiKeyFilePath ( tl . getInput ( 'apiKeyId' , true ) ) ; apiKey = { key_id : tl . getInput ( 'apiKeyId' , true ) , issuer_id : tl . getInput ( 'apiKeyIssuerId' , true ) , key : tl . getInput ( 'apitoken' , true ) , in_house : tl . getBoolInput ( 'apiKeyInHouse' , false ) , is_key_content_base64 : true } ; } let appIdentifier = tl . getInput ( 'appIdentifier' , true ) ; let chooseBuild = tl . getInput ( 'chooseBuild' , true ) ; let buildNumber = tl . getInput ( 'buildNumber' , false ) ; let shouldAutoRelease = tl . getBoolInput ( 'shouldAutoRelease' , false ) ; let teamId = tl . getInput ( 'teamId' , false ) ; let teamName = tl . getInput ( 'teamName' , false ) ; let installFastlane = tl . getBoolInput ( 'installFastlane' , false ) ; let fastlaneVersionChoice = tl . getInput ( 'fastlaneToolsVersion' , false ) ; let fastlaneVersionToInstall ; if ( fastlaneVersionChoice === 'SpecificVersion' ) { fastlaneVersionToInstall = tl . getInput ( 'fastlaneToolsSpecificVersion' , true ) ; } let fastlaneArguments = tl . getInput ( 'fastlaneArguments' ) ; tl . debug ( 'Read all inputs.' ) ; tl . debug ( `GEM_CACHE=${ process . env [ 'GEM_CACHE' ] }` ) ; let gemCache = process . env [ 'GEM_CACHE' ] || path . join ( process . env [ 'HOME' ] , '.gem-cache' ) ; tl . debug ( `gemCache=${ gemCache }` ) ; process . env [ 'GEM_HOME' ] = gemCache ; process . env [ 'FASTLANE_PASSWORD' ] = credentials . password ; process . env [ 'FASTLANE_DONT_STORE_PASSWORD' ] = 'true' ; if ( isTwoFactorAuthEnabled ) { tl . debug ( 'Using two-factor authentication' ) ; process . env [ fastlaneSessionEnvVar ] = credentials . fastlaneSession ; process . env [ appSpecificPasswordEnvVar ] = credentials . appSpecificPassword ; } process . env [ 'PATH' ] = process . env [ 'PATH' ] + ':' + gemCache + path . sep + 'bin' ; tl . debug ( 'Checking for ruby install...' ) ; tl . which ( 'ruby' , true ) ; if ( installFastlane && fastlaneVersionToInstall ) { try { let gemRunner = tl . tool ( tl . which ( 'gem' , true ) ) ; gemRunner . arg ( [ 'uninstall' , 'fastlane' ] ) ; tl . debug ( `Uninstalling all fastlane versions...` ) ; gemRunner . arg ( [ '-a' , '-I' ] ) ; await gemRunner . exec ( ) ; } catch ( err ) { tl . warning ( tl . loc ( 'UninstallFastlaneFailed' , err ) ) ; } } if ( installFastlane ) { tl . debug ( 'Installing fastlane...' ) ; let gemRunner = tl . tool ( tl . which ( 'gem' , true ) ) ; gemRunner . arg ( [ 'install' , 'fastlane' ] ) ; if ( fastlaneVersionToInstall ) { tl . debug ( `Installing specific version of fastlane: ${ fastlaneVersionToInstall }` ) ; gemRunner . arg ( [ '-v' , fastlaneVersionToInstall ] ) ; } await gemRunner . exec ( ) ; if ( ! fastlaneVersionToInstall ) { tl . debug ( 'Updating fastlane...' ) ; gemRunner = tl . tool ( tl . which ( 'gem' , true ) ) ; gemRunner . arg ( [ 'update' , 'fastlane' , '-i' , gemCache ] ) ; await gemRunner . exec ( ) ; } } else { tl . debug ( 'Skipped fastlane installation.' ) ; } let deliverCommand = tl . tool ( 'fastlane' ) ; if ( isUsingApiKey ) { if ( fs . existsSync ( apiKeyFilePath ) ) { fs . unlinkSync ( apiKeyFilePath ) ; } let apiKeyJsonData = JSON . stringify ( apiKey ) ; fs . writeFileSync ( apiKeyFilePath , apiKeyJsonData ) ; console . log ( tl . loc ( 'PrecheckInAppPurchasesDisabled' ) ) ; deliverCommand . arg ( [ 'deliver' , 'submit_build' , '--precheck_include_in_app_purchases' , 'false' , '--api_key_path' , apiKeyFilePath , '-a' , appIdentifier ] ) ; } else { deliverCommand . arg ( [ 'deliver' , 'submit_build' , '-u' , credentials . username , '-a' , appIdentifier ] ) ; } if ( chooseBuild . toLowerCase ( ) === 'specify' ) { deliverCommand . arg ( [ '-n' , buildNumber ] ) ; } deliverCommand . arg ( [ '--skip_binary_upload' , 'true' , '--skip_metadata' , 'true' , '--skip_screenshots' , 'true' ] ) ; deliverCommand . argIf ( shouldAutoRelease , '--automatic_release' ) ; deliverCommand . argIf ( teamId , [ '-k' , teamId ] ) ; deliverCommand . argIf ( teamName , [ '--team_name' , teamName ] ) ; deliverCommand . arg ( '--force' ) ; if ( fastlaneArguments ) { deliverCommand . line ( fastlaneArguments ) ; } await deliverCommand . exec ( ) ; tl . setResult ( tl . TaskResult . Succeeded , tl . loc ( 'SuccessfullySubmitted' ) ) ; } catch ( err ) { tl . setResult ( tl . TaskResult . Failed , err ) ; } finally { if ( isTwoFactorAuthEnabled ) { tl . debug ( 'Clearing two-factor authentication environment variables' ) ; process . env [ fastlaneSessionEnvVar ] = '' ; process . env [ appSpecificPasswordEnvVar ] = '' ; } if ( isUsingApiKey && apiKeyFilePath && process . env [ 'DEBUG_API_KEY_FILE' ] !== 'true' ) { tl . debug ( 'Clearing API Key file' ) ; if ( fs . existsSync ( apiKeyFilePath ) ) { fs . unlinkSync ( apiKeyFilePath ) ; } } } } run ( ) ;