Skip to content

Instantly share code, notes, and snippets.

@ngs
Forked from kishikawakatsumi/Rakefile
Last active August 29, 2015 14:06
Show Gist options
  • Save ngs/c690488e90bfe1a8f6d2 to your computer and use it in GitHub Desktop.
Save ngs/c690488e90bfe1a8f6d2 to your computer and use it in GitHub Desktop.
require "rubygems/version"
require "rake/clean"
require "date"
# Application info
APP_NAME = "Ubiregi2"
SDK = "iphoneos"
WORKSPACE = File.expand_path("#{APP_NAME}.xcworkspace")
SCHEME = "#{APP_NAME}-Release"
INFO_PLIST = File.expand_path("#{APP_NAME}/#{APP_NAME}-Info.plist")
REPO = "ubiregiinc/ubiregi-client"
# Code signing
CODE_SIGN_IDENTITY_APPSTORE = "iPhone Distribution: XXXXX Inc. (XXXXXXXXXX)";
CODE_SIGN_IDENTITY_INHOUSE = "iPhone Distribution: XXXXX K.K.";
PROFILE_APPSTORE = "#{APP_NAME}_App_Store.mobileprovision"
PROFILE_ADHOC = "#{APP_NAME}_Ad_Hoc.mobileprovision"
PROFILE_INHOUSE = "#{APP_NAME}_Beta.mobileprovision"
PROFILE_NAME_ADHOC = "#{APP_NAME} Ad Hoc"
PROFILE_DIR = "$HOME/Library/MobileDevice/Provisioning Profiles"
KEYCHAIN_NAME = "ios-build.keychain"
# Build paths
BUILD_DIR = File.expand_path("build")
APP_FILE = File.expand_path("#{BUILD_DIR}/#{APP_NAME}.app")
ARCHIVE_FILE = File.expand_path("#{BUILD_DIR}/#{APP_NAME}.xcarchive")
IPA_FILE = File.expand_path("#{BUILD_DIR}/#{APP_NAME}.ipa")
DSYM_FILE = File.expand_path("#{BUILD_DIR}/#{APP_NAME}.app.dSYM")
DSYM_ZIP_FILE = File.expand_path("#{BUILD_DIR}/#{APP_NAME}.app.dSYM.zip")
# Test info
DESTINATIONS = [
"name=iPad,OS=7.1",
"name=iPad Retina,OS=7.1",
"name=iPad Retina (64-bit),OS=7.1",
]
# Crittercism info
APP_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# TestFlight info
API_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
TEAM_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CLEAN.include(BUILD_DIR)
CLOBBER.include(BUILD_DIR)
task :default => [:build]
desc "Setting up a development environment"
task :setup do
sh "bundle install"
sh "pod install"
end
desc "Test application"
task test: ["test:release"]
namespace :test do
task :release do
test(configuration: "Release")
end
task :debug do
test(configuration: "Debug")
end
task :adhoc do
test(configuration: "AdHoc")
end
end
def test(configuration: "Release")
options = build_options(sdk: "iphonesimulator", configuration: configuration)
options << DESTINATIONS.map { |destination| %[-destination "#{destination}"] }.join(" ")
sh %[xcodebuild #{options} GCC_SYMBOLS_PRIVATE_EXTERN="NO" test | xcpretty -c; exit ${PIPESTATUS[0]}]
end
desc "Build application (Release)"
task build: ["build:release"]
namespace :build do
desc "Build application (Release)"
task :release do
build
end
desc "Build application (AdHoc)"
task :adhoc do
build(configuration: "AdHoc")
end
end
def build(configuration: "Release")
options = build_options(configuration: configuration)
settings = build_settings(configuration: configuration)
sh %[xcodebuild #{options} #{settings} build | xcpretty -c; exit ${PIPESTATUS[0]}]
end
desc "Build artifacts (.xcarchive, ipa) (Release)"
task archive: ["archive:release"]
namespace :archive do
desc "Build artifacts (.xcarchive, ipa) (Release)"
task :release do
archive
end
desc "Build artifacts (.xcarchive, ipa) (AdHoc)"
task :adhoc do
archive(configuration: "AdHoc")
end
end
def archive(configuration: "Release")
build_xcarchive(configuration: configuration)
clean_ipa
export_ipa
zip_dsyms
end
def build_xcarchive(configuration: "Release")
options = build_options(configuration: configuration)
settings = build_settings(configuration: configuration)
sh %[xcodebuild #{options} #{settings} archive -archivePath #{ARCHIVE_FILE} | xcpretty -c; exit ${PIPESTATUS[0]}]
end
def clean_ipa
system "rm -f #{IPA_FILE}"
end
def export_ipa
sh %[xcodebuild -exportArchive #{export_options} | xcpretty -c; exit ${PIPESTATUS[0]}]
end
def export_options(configuration: "Release", **others)
options = {
exportFormat: "IPA",
archivePath: ARCHIVE_FILE,
exportPath: IPA_FILE,
exportProvisioningProfile: PROFILE_NAME_ADHOC,
}.merge others
join_options(options: options, prefix: "-", separator: " ")
end
def resign_ipa
sh %[unzip -o #{IPA_FILE} -d build 1>/dev/null]
sh %[rm -rf #{BUILD_DIR}/Payload/#{APP_NAME}.app/_CodeSignature/]
sh %[cp #{PROFILE_ADHOC} #{BUILD_DIR}/Payload/#{APP_NAME}.app/embedded.mobileprovision]
sh %[codesign --verify --force --sign "#{CODE_SIGN_IDENTITY_APPSTORE}" --resource-rules #{BUILD_DIR}/Payload/#{APP_NAME}.app/ResourceRules.plist #{BUILD_DIR}/Payload/#{APP_NAME}.app]
sh %[(cd #{BUILD_DIR}; zip -ryq #{APP_NAME}.ipa Payload)]
end
def zip_dsyms
sh "(cd #{BUILD_DIR}; zip -ryq #{APP_NAME}.app.dSYM.zip #{APP_NAME}.app.dSYM)"
sh "mv #{DSYM_FILE} #{BUILD_DIR}/#{APP_NAME}.xcarchive/dSYMs/#{APP_NAME}.app.dSYM"
sh "(cd #{BUILD_DIR}; zip -ryq #{APP_NAME}.xcarchive.zip #{APP_NAME}.xcarchive)"
end
def build_options(configuration: "Release", **others)
options = {
sdk: SDK,
workspace: WORKSPACE,
scheme: SCHEME,
configuration: configuration,
}.merge others
join_options(options: options, prefix: "-", separator: " ")
end
def build_settings(configuration: "Release")
code_sign_identity = configuration == "Release" ? CODE_SIGN_IDENTITY_APPSTORE : CODE_SIGN_IDENTITY_INHOUSE
settings = {
CONFIGURATION_BUILD_DIR: BUILD_DIR,
CONFIGURATION_TEMP_DIR: "#{BUILD_DIR}/temp",
CODE_SIGN_IDENTITY: code_sign_identity,
}
settings = join_options(options: settings, prefix: "", separator: "=")
end
desc "Upload IPA file to TestFlight (Release)"
task distribute: ["distribute:release"]
namespace :distribute do
desc "Upload IPA file to TestFlight (Release)"
task :release => ["archive:release"] do
distribute
end
desc "Upload IPA file to TestFlight (AdHoc)"
task :adhoc => ["version:set_build_version", "archive:adhoc"] do
distribute
end
end
def distribute
crittercism
testflight
end
def crittercism
options = {
dsym: "@#{DSYM_ZIP_FILE}",
key: API_KEY,
}
upload_form("https://api.crittercism.com/api_beta/dsym/#{APP_ID}", options)
end
def testflight
pr_number = ENV["TRAVIS_PULL_REQUEST"]
branch_name = ENV["TRAVIS_BRANCH"]
release_date = DateTime.now.strftime("%Y/%m/%d %H:%M:%S")
build_version = InfoPlist.marketing_and_build_version
repo_url = "https://github.com/#{REPO}"
release_notes = "Build: #{build_version}\nUploaded: #{release_date}\n"
if pull_request?
release_notes << "Branch: #{repo_url}/commits/#{branch_name}\n"
release_notes << "Pull Request: #{repo_url}/pull/#{pr_number}\n"
release_notes << %x[git log --date=short --pretty=format:"* %h - %s (%cd) <%an>" --no-merges #{branch_name}..]
else
commit_hash = %x[git rev-parse HEAD].strip
release_notes << "Branch: #{repo_url}/commits/#{branch_name}\n"
if branch_name == "master"
release_notes << %x[git log --date=short --pretty=format:"* %h - %s (%cd) <%an>" --no-merges $(git describe --abbrev=0 --tags)..]
else
release_notes << %x[git log --date=short --pretty=format:"* %h - %s (%cd) <%an>" --no-merges]
end
end
options = {
file: "@#{IPA_FILE}",
api_token: API_TOKEN,
team_token: TEAM_TOKEN,
notify: true,
replace: true,
distribution_lists: pull_request? ? "Dev" : "Internal",
notes: release_notes,
}
upload_form("http://testflightapp.com/api/builds.json", options)
end
def upload_form(url, options = {})
curl_options = ["curl", "-sL", "-w", "%{http_code} %{url_effective}\\n", "#{url}"]
form_fields = options.flat_map { |k, v| ["-F", "#{k}=#{v}"] }
output_options = ["-o", "/dev/null"]
sh *(curl_options + form_fields + output_options)
end
desc "Submit application"
task :release do
sh "git checkout -b release/$(git rev-parse --short HEAD)"
InfoPlist.bump_release_version
InfoPlist.update_build_number
InfoPlist.commit
branch_name = "release/#{InfoPlist.marketing_version}"
sh "git branch -M #{branch_name}"
sh "git push [email protected]:#{REPO}.git #{branch_name}"
end
namespace :profile do
desc "Download provisioning profiles from Apple Developer Center"
task :download do
profile_download("[email protected]", "xxxxxxxxxxxxxxxxxx")
end
task :install do
profile_install
end
end
def profile_download(user, passowrd)
system "ios profiles:download:all -u #{user} -p #{password} --type distribution"
end
def profile_install
sh %[mkdir -p "#{PROFILE_DIR}"]
sh %[cp "#{PROFILE_INHOUSE}" "#{PROFILE_DIR}"]
sh %[cp "#{PROFILE_ADHOC}" "#{PROFILE_DIR}"]
end
namespace :certificate do
task :add do
add_certificates
end
task :remove do
remove_certificates
end
end
def add_certificates
passphrase = "xxxxxxxx"
sh "security create-keychain -p travis #{KEYCHAIN_NAME}"
sh "security import ./certificates/apple.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
sh "security import ./certificates/appstore.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
sh "security import ./certificates/appstore.p12 -k #{KEYCHAIN_NAME} -P #{passphrase} -T /usr/bin/codesign"
sh "security import ./certificates/inhouse.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
sh "security import ./certificates/inhouse.p12 -k #{KEYCHAIN_NAME} -P #{passphrase} -T /usr/bin/codesign"
sh "security default-keychain -s #{KEYCHAIN_NAME}"
end
def remove_certificates
sh "security delete-keychain #{KEYCHAIN_NAME}"
end
def pull_request?
pr_number = ENV["TRAVIS_PULL_REQUEST"]
pr_number != nil && !pr_number.empty? && pr_number != "false"
end
def join_options(options: {}, prefix: "", separator: "")
options.map { |k, v| %(#{prefix}#{k}#{separator}"#{v}") }.join(" ")
end
namespace :version do
module InfoPlist
extend self
def [](key)
output = %x[/usr/libexec/PlistBuddy -c "Print #{key}" #{INFO_PLIST}].strip
raise "The key `#{key}' does not exist in `#{INFO_PLIST}'." if output.include?('Does Not Exist')
output
end
def set(key, value, file = "#{INFO_PLIST}")
%x[/usr/libexec/PlistBuddy -c 'Set :#{key} "#{value}"' '#{file}'].strip
end
def []=(key, value)
set(key, value)
end
def build_version
self['CFBundleVersion']
end
def build_version=(revision)
self['CFBundleVersion'] = revision
end
def marketing_version
self['CFBundleShortVersionString']
end
def marketing_version=(version)
self['CFBundleShortVersionString'] = version
end
def marketing_and_build_version
"#{marketing_version} (#{build_version})"
end
def bump_minor_version
segments = Gem::Version.new(marketing_version).segments
segments[1] = "%02d" % (segments[1].to_i + 1)
version = segments.join('.')
self.marketing_version = version
segments[1]
end
def bump_major_version
segments = Gem::Version.new(marketing_version).segments
segments[0] = segments[0].to_i + 1
segments[1] = "00"
version = segments.join('.')
self.marketing_version = version
segments[0]
end
def bump_release_version
if bump_minor_version.to_i.odd?
bump_minor_version
end
end
def update_build_number
build_number = %x[git rev-list HEAD | wc -l | tr -d " "].strip
self.build_version = build_number.to_s
end
def commit
system("git commit #{INFO_PLIST} -m 'Bump to #{marketing_and_build_version}'")
end
end
desc "Print the current version"
task :current do
puts InfoPlist.marketing_and_build_version
end
desc "Sets build version to last git commit (happens on each build)"
task :set_build_version do
rev = ""
pr_number = ENV["TRAVIS_PULL_REQUEST"]
if pull_request?
rev << %x[git rev-parse --short HEAD^2].strip
rev << " ##{pr_number}"
else
rev << %x[git rev-parse --short HEAD].strip
end
puts "Setting build version to: #{rev}"
InfoPlist.build_version = rev
end
namespace :bump do
desc "Bump minor version (0.XX)"
task :minor do
InfoPlist.bump_minor_version
InfoPlist.update_build_number
InfoPlist.commit
end
desc "Bump major version (X.00)"
task :major do
InfoPlist.bump_major_version
InfoPlist.update_build_number
InfoPlist.commit
end
desc "Bump release version (0.XY)"
task :release do
InfoPlist.bump_release_version
InfoPlist.update_build_number
InfoPlist.commit
end
end
end
desc "Print the current version"
task :version => 'version:current'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment