in Tasks/IpaResign/ipa-resign.ts [22:231]
async function run() {
let deleteKeychain: boolean = false;
let useKeychain: string;
let deleteProvProfile: boolean = false;
let useProvProfilePath: string;
try {
tl.setResourcePath(path.join( __dirname, 'task.json'));
// Check if this is running on Mac and fail the task if not
if (os.platform() !== 'darwin') {
throw new Error(tl.loc('DarwinOnly'));
}
// Get input variables
let ipaPath: string = tl.getPathInput('ipaPath', true, false);
let signMethod: string = tl.getInput('signMethod', true);
let signFileP12Path: string;
let signFileP12Password: string;
let signIdIdentity: string;
let signIdUnlockKeychain: boolean = false;
let signIdKeychainPassword: string;
if (signMethod === 'file') {
signFileP12Path = tl.getPathInput('signFileP12Path', true, false);
// Ensure signFileP12Path is actually a path
if (!tl.filePathSupplied('signFileP12Path')) {
throw new Error(tl.loc('P12FilePathNotAPath', signFileP12Path));
}
signFileP12Password = tl.getInput('signFileP12Password', true);
} else if (signMethod === 'id') {
signIdIdentity = tl.getInput('signIdIdentity', true);
signIdUnlockKeychain = tl.getBoolInput('signIdUnlockKeychain', false);
signIdKeychainPassword = tl.getInput('signIdKeychainPassword', false);
}
let provisionMethod: string = tl.getInput('provisionMethod', true);
let provFileProfilePath: string;
let provFileRemoveProfile: boolean = false;
let provIdProfileUuid: string;
if (provisionMethod === 'file') {
provFileRemoveProfile = tl.getBoolInput('provFileRemoveProfile', false);
provFileProfilePath = tl.getPathInput('provFileProfilePath', true, false);
// Ensure provFileProfilePath is actually a path
if (!tl.filePathSupplied('provFileProfilePath')) {
throw new Error(tl.loc('ProvisionFilePathNotAPath', provFileProfilePath));
}
} else if (provisionMethod === 'id') {
provIdProfileUuid = tl.getInput('provIdProfileUuid', true);
}
let entitlementsPath: string;
if (tl.filePathSupplied('entitlementsPath')) {
entitlementsPath = tl.getPathInput('entitlementsPath', false, false);
}
let sighResignArgs: string = tl.getInput('sighResignArgs', false);
let cwdPath: string = tl.getInput('cwdPath', false);
// Process working directory
let cwd: string = cwdPath
|| tl.getVariable('build.sourceDirectory')
|| tl.getVariable('build.sourcesDirectory')
|| tl.getVariable('System.DefaultWorkingDirectory');
tl.cd(cwd);
tl.debug('cwd = ' + cwd);
// Find the absolute ipa file path
let useIpaPath: string = findMatchExactlyOne(cwd, ipaPath);
// Determine the params used when resigning based on sign method.
let useSigningIdentity = null;
if (signMethod === 'file') {
let signFilePath: string = findMatchExactlyOne(cwd, signFileP12Path);
let keychain: string = tl.resolve(cwd, '_iparesigntasktmp.keychain');
let keychainPwd: string = '_iparesigntask_TmpKeychain_Pwd#1';
// Create a temporary keychain and install the p12 into that keychain
tl.debug('installed cert in temp keychain');
await sign.installCertInTemporaryKeychain(keychain, keychainPwd, signFilePath, signFileP12Password);
useKeychain = keychain;
deleteKeychain = true;
useSigningIdentity = await sign.findSigningIdentity(keychain);
} else if (signMethod === 'id') {
let defaultKeychain: string = await sign.getDefaultKeychainPath();
if (signIdUnlockKeychain) {
await sign.unlockKeychain(defaultKeychain, signIdKeychainPassword);
}
useKeychain = defaultKeychain;
useSigningIdentity = signIdIdentity;
}
// Determine the params used when resigning based on provision method.
if (provisionMethod === 'file') {
useProvProfilePath = findMatchExactlyOne(cwd, provFileProfilePath);
deleteProvProfile = provFileRemoveProfile;
} else if (provisionMethod === 'id') {
// Gets the provisioning profile from the default path by uuid (~/Library/MobileDevice/Provisioning Profiles).
useProvProfilePath = sign.getProvisioningProfilePath(provIdProfileUuid);
}
// Find the absolute entitlements file path.
let useEntitlementsFilePath: string;
if (entitlementsPath) {
useEntitlementsFilePath = findMatchExactlyOne(cwd, entitlementsPath);
}
// Having all the params ready configure the environment and exec fastlane sigh resign.
// Set up environment
tl.debug(`GEM_CACHE=${process.env['GEM_CACHE']}`);
let gemCache: string = process.env['GEM_CACHE'] || path.join(process.env['HOME'], '.gem-cache');
tl.debug(`gemCache=${gemCache}`);
process.env['GEM_HOME'] = gemCache;
process.env['FASTLANE_DISABLE_COLORS'] = 'true';
// Add bin of new gem home so we don't ahve to resolve it later;
process.env['PATH'] = process.env['PATH'] + ':' + gemCache + path.sep + 'bin';
let installFastlane: boolean = tl.getBoolInput('installFastlane', false);
let fastlaneVersionChoice: string = tl.getInput('fastlaneToolsVersion', false);
let fastlaneVersionToInstall: string; //defaults to 'LatestVersion'
if (fastlaneVersionChoice === 'SpecificVersion') {
fastlaneVersionToInstall = tl.getInput('fastlaneToolsSpecificVersion', true);
}
// Install the ruby gem for fastlane
tl.debug('Checking for ruby install...');
tl.which('ruby', true);
//Whenever a specific version of fastlane is requested, we're going to attempt to uninstall any installed
//versions of fastlane. Note that this doesn't uninstall dependencies of fastlane.
if (installFastlane && fastlaneVersionToInstall) {
try {
let gemRunner: ToolRunner = tl.tool(tl.which('gem', true));
gemRunner.arg(['uninstall', 'fastlane']);
tl.debug(`Uninstalling all fastlane versions...`);
gemRunner.arg(['-a', '-I']); //uninstall all versions
await gemRunner.exec();
} catch (err) {
tl.warning(tl.loc('UninstallFastlaneFailed', err));
}
}
// If desired, install the fastlane tools (if they're already present, should be a no-op)
if (installFastlane) {
tl.debug('Installing fastlane...');
let gemRunner: ToolRunner = 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 desired, update fastlane (if already latest, should be a no-op)
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.');
}
// Run the sigh command
// See https://github.com/fastlane/fastlane/tree/master/sigh for more information on these arguments
let sighCommand: ToolRunner = tl.tool('fastlane');
sighCommand.arg(['sigh']);
sighCommand.arg(['resign', useIpaPath]);
sighCommand.arg(['--keychain_path', useKeychain]);
sighCommand.arg(['--signing_identity', useSigningIdentity]);
sighCommand.arg(['--provisioning_profile', useProvProfilePath]);
sighCommand.argIf(useEntitlementsFilePath, ['--entitlements', useEntitlementsFilePath]);
if (sighResignArgs) {
sighCommand.line(sighResignArgs);
}
await sighCommand.exec();
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SuccessfullyResigned', useIpaPath));
} catch (err) {
tl.setResult(tl.TaskResult.Failed, err);
} finally {
// Clean up the temporary keychain, so it is not used to search for code signing identity in the future.
if (deleteKeychain) {
try {
await sign.deleteKeychain(useKeychain);
} catch (err) {
tl.debug('Failed to delete temporary keychain. Error = ' + err);
tl.warning(tl.loc('FailedTemporaryKeyDeletion', useKeychain));
}
}
// Delete provisioning profile if specified
if (deleteProvProfile) {
try {
await sign.deleteProvisioningProfile(useProvProfilePath);
} catch (err) {
tl.debug('Failed to delete provisioning profile. Error = ' + err);
tl.warning(tl.loc('FailedProvisioningProfileDeletion', useProvProfilePath));
}
}
}
}