Created
August 3, 2012 09:12
-
-
Save benchester/3246142 to your computer and use it in GitHub Desktop.
script for uploading to Hockey from Jenkins
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//==== USAGE ===== | |
// -w "Workspace" - required | |
// -t "Title" - required | |
// -r "Release type" - optional (2:Alpha, 0:Beta, 1:Live) | |
// -n "Notes" - optional | |
// -v no arguments, enable for logging | |
//==== JENKINS SETUP ==== | |
// 1) Install Jenkins Post build task plugin | |
// https://wiki.jenkins-ci.org/display/JENKINS/Post+build+task | |
// 2) Add post build task: | |
// cd .. | |
// php script.php -w ${WORKSPACE} -t ${JOB_NAME} -r "0" -n ${BUILD_ID} -v | |
// This should be your app token for all apps | |
$appToken = "INSERT_TOKEN_HERE"; | |
//============================================ | |
// Get cmd line args | |
//============================================ | |
$opts = "w:"; // workspace - required | |
$opts .= "t:"; // title - required for creating a new app | |
$opts .= "r::"; // release type - optional | |
$opts .= "n::"; // notes - optional | |
$opts .= "v"; // verbose - for logging | |
$options = getopt($opts); | |
// get cmdline args | |
$workspace = $options[w]; | |
// trim workspace path | |
$path_array = explode("/", $workspace); | |
$project_dir = $path_array[count($path_array) - 1]; | |
$title = $options[t]; | |
$release_type = $options[r]; | |
$notes = $options[n]; | |
// default to Beta | |
if (strlen($release_type) == 0) | |
{ | |
$release_type = "0"; | |
} | |
// default notes | |
if (strlen($notes) == 0) | |
{ | |
$notes = "default note"; | |
} | |
if ($options[v] == false) | |
{ | |
$verbose = true; | |
} | |
else | |
{ | |
$verbose = false; | |
} | |
//============================================ | |
// Utility functions | |
//============================================ | |
/* | |
* Recursive glob() (from php.net) | |
*/ | |
function rglob($pattern='*', $flags = 0, $path='') | |
{ | |
$paths = glob($path.'*', GLOB_MARK|GLOB_ONLYDIR|GLOB_NOSORT); | |
$files = glob($path.$pattern, $flags); | |
foreach ($paths as $path) { $files = array_merge($files, rglob($pattern, $flags, $path)); } | |
return $files; | |
} | |
// Set up curl | |
function connectSetup($url) | |
{ | |
global $appToken; | |
$c = curl_init($url); | |
curl_setopt($c, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false); | |
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); | |
curl_setopt($c, CURLOPT_HTTPHEADER, array("X-HockeyAppToken: ".$appToken)); | |
return $c; | |
} | |
function getPlatform() | |
{ | |
$platform = new stdClass(); | |
foreach(rglob("*.ipa") as $ipa){} | |
foreach(rglob("*.apk") as $apk){} | |
if (!empty($ipa)) | |
{ | |
$platform = "iOS"; | |
} | |
else if (!empty($apk)) | |
{ | |
$platform = "Android"; | |
} | |
return $platform; | |
} | |
//============================================ | |
// Pre-upload functions | |
//============================================ | |
// returns target array for Android | |
// (Assuming there will never be multiple targets) | |
function getAndroidTarget() | |
{ | |
$target = new stdClass(); | |
foreach (rglob("*.apk") as $current) | |
{ | |
// ignore unsigned and unaligned apks | |
if (!preg_match('/unaligned/', $current) && !preg_match('/unsigned/', $current)) | |
{ | |
$apk = $current; | |
$path_array = explode("/", $apk); | |
// get base folder containing apk | |
$basename = $path_array[0]; | |
// get path to Android.manifest in base folder | |
foreach (rglob("AndroidManifest.xml", 0, $basename) as $manifest) {} | |
// read from .manifest | |
$handle = @fopen($manifest, "r"); | |
if ($handle) | |
{ | |
while (($buffer = fgets($handle, 4096)) !== false) | |
{ | |
if (substr_count($buffer, "package") == 1) | |
{ | |
$bundleID = str_replace("package=", "", $buffer); | |
$bundleID = str_replace("\"", "", $bundleID); | |
$bundleID = trim($bundleID); | |
$target = array( | |
'bundleID' =>$bundleID, | |
'apk' =>$apk, | |
'manifest' =>$manifest | |
); | |
} | |
} | |
} | |
} | |
} | |
return $target; | |
} | |
// returns array of target arrays for iOS | |
function getiOSTargets() | |
{ | |
$targets = array(); | |
foreach (rglob("*.plist") as $plist) | |
{ | |
// use Info.plists in .app.dSYMs in build directory | |
if (preg_match('/build/', $plist) && preg_match('/Info/', $plist)) | |
{ | |
// read from .plist | |
$handle = @fopen($plist, "r"); | |
if ($handle) | |
{ | |
while (($buffer = fgets($handle, 4096)) !== false) { | |
// if we've found the bundle id, get the next line | |
if (substr_count($buffer, "CFBundleIdentifier") == 1) | |
{ | |
if (($buffer = fgets($handle, 4096)) !== false) | |
{ | |
// trim the bundleID | |
$bundleID = str_replace("<string>", "", $buffer); | |
$bundleID = str_replace("</string>", "", $bundleID); | |
$bundleID = trim($bundleID); | |
// if the bundleID is unique and is real (check for com) | |
if (!in_array($bundleID, $targets) && preg_match('/com/', $bundleID)) | |
{ | |
$bundleID = str_replace("com.apple.xcode.dsym.","",$bundleID); | |
// Trim plist path to just app name | |
$path_array = explode("/", $plist); | |
foreach ($path_array as $string) | |
{ | |
if (substr_count($string, ".app.dSYM") == 1) | |
{ | |
$baseString = str_replace(".app.dSYM", "", $string); | |
} | |
} | |
// find matching ipa and dSYM.zip files | |
// If there are multiple matches, this will use the last match | |
// Match assumes there will be a - directly after baseString | |
// e.g. MYO2Ref-Release-3.0-dSYM.zip, MyO2-Release-3.0.ipa | |
foreach (rglob($baseString."-*dSYM.zip") as $dsym) {} | |
foreach (rglob($baseString."-*.ipa") as $ipa) {} | |
array_push($targets, | |
array( | |
'bundleID' =>$bundleID, | |
'dsym' =>$dsym, | |
'ipa' => $ipa, | |
'plist' => $plist | |
)); | |
} | |
} | |
} | |
} | |
if (!feof($handle)) { | |
echo "Error: unexpected fgets() fail\n"; | |
} | |
fclose($handle); | |
} | |
} | |
} | |
//var_dump($targets); | |
return $targets; | |
} | |
// Returns array of apps from HockeyApp | |
function getApps() | |
{ | |
$url = "https://rink.hockeyapp.net/api/2/apps/"; | |
$c = connectSetup($url); | |
$result = curl_exec($c); | |
$json = json_decode($result); | |
curl_close($c); | |
return $json->apps; | |
} | |
// Checks whether bundleID is in apps array (UNUSED) | |
// If bundleID exists, return app, otherwise return stdClass | |
// returned object contains bundle, platform, publicid, title [etc] | |
function appForBundleID($bundleID, $apps) | |
{ | |
$return = new stdClass(); | |
foreach ($apps as $app) | |
{ | |
if (strcmp($app->bundle_identifier, $bundleID) == 0) | |
{ | |
$return = $app; | |
} | |
} | |
return $return; | |
} | |
//============================================ | |
// Upload functions | |
//============================================ | |
// Creates a new app (UNUSED) | |
// platform = iOS, Android, Mac OS, Windows Phone, Custom | |
// release_type = 2:Alpha, 0:Beta, 1:Live | |
function newApp($title, $bundle_identifier, $platform, $release_type) | |
{ | |
$url = "https://rink.hockeyapp.net/api/2/apps/new"; | |
$c = connectSetup($url); | |
$data = array( | |
'title' => $title, | |
'bundle_identifier' => $bundle_identifier, | |
'platform' => $platform, | |
'release_type' => $release_type | |
); | |
curl_setopt($c, CURLOPT_POSTFIELDS, $data); | |
$result = curl_exec($c); | |
curl_close($c); | |
$json = json_decode($result); | |
return $json; | |
} | |
// Uploads with notes, ipa, and dsym | |
function uploadApp($ipa, $dsym, $notes) | |
{ | |
$url = "https://rink.hockeyapp.net/api/2/apps/"; | |
$c = connectSetup($url); | |
$data = array( | |
'status' =>'2', | |
'notify' =>'1', | |
'notes' => $notes, | |
'notes_type' => '0', | |
'ipa' => "@".$ipa | |
//'dsym' => "@".$dsym | |
); | |
$dsym_array = (array)$dsym; | |
if (!empty($dsym_array)) | |
{ | |
array_push($data, $data['dsym']="@".$dsym); | |
} | |
curl_setopt($c, CURLOPT_POSTFIELDS, $data); | |
$result = curl_exec($c); | |
curl_close($c); | |
$json = json_decode($result); | |
return $json; | |
} | |
//============================================ | |
// Upload to Hockey | |
//============================================ | |
// change current directory to project directory | |
chdir("../".$project_dir); | |
if ($verbose) | |
echo "Current working directory: ".getcwd()."\n"; | |
// get apps on Hockey | |
$apps = getApps(); | |
// get platform | |
$platform = getPlatform(); | |
if ($verbose) | |
echo "Platform detected: ".$platform."\n"; | |
// For iOS | |
if (strcmp($platform, "iOS")==0) | |
{ | |
// get targets in project directory | |
$targets = getiOSTargets(); | |
if ($verbose){ | |
echo count($targets)." iOS targets found:\n"; | |
print_r($targets);} | |
// iterate through targets | |
foreach ($targets as $currentTarget) { | |
$bundleID = $currentTarget['bundleID']; | |
$ipa = $currentTarget['ipa']; | |
$dsym = $currentTarget['dsym']; | |
// check bundleID against Hockey apps (UNUSED) | |
//$app = appForBundleID($bundleID, $apps); | |
echo "Uploading app with bundleID: ".$bundleID."\n"; | |
echo "JSON response: \n"; | |
print_r(uploadApp($ipa, $dsym, $notes)); | |
echo "\n"; | |
} | |
} | |
else if (strcmp($platform, "Android")==0) | |
{ | |
// get target in project directory | |
$target = getAndroidTarget(); | |
if ($verbose){ | |
echo "Android target:\n"; | |
print_r($target)."\n";} | |
$bundleID = $target['bundleID']; | |
$apk = $target['apk']; | |
// no dSYM on android | |
$dsym = new stdClass(); | |
// check bundleID against Hockey apps (UNUSED) | |
//$app = appForBundleID($bundleID, $apps); | |
echo "Uploading app with bundleID: ".$bundleID."\n"; | |
echo "JSON response:\n"; | |
print_r(uploadApp($apk, $dsym, $notes)); | |
echo "\n"; | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment