Skip to content

Instantly share code, notes, and snippets.

@oinariman
Last active December 30, 2023 06:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oinariman/d63566eda7a8c7d8ce0c323e8b3a023d to your computer and use it in GitHub Desktop.
Save oinariman/d63566eda7a8c7d8ce0c323e8b3a023d to your computer and use it in GitHub Desktop.
require 'json'
require 'jwt'
require 'net/http'
APP_ID = ARGV[0]
KEY_ID = ARGV[1]
ISSUER_ID = ARGV[2]
AUTH_KEY_PATH = ARGV[3]
FETCH_LOCALES = ARGV.length == 4
VERSION = ARGV[4]
TOKEN_LIFETIME = 600 # 10 minutes (up to 20 minutes allowed by Apple)
HTTP_METHODS = {
get: Net::HTTP::Get,
post: Net::HTTP::Post,
patch: Net::HTTP::Patch,
}
$token = nil
def make_token
header = {
"alg": "ES256",
"kid": KEY_ID,
"typ": "JWT"
}
now = Time.now.to_i
payload = {
"iss": ISSUER_ID,
"iat": now,
"exp": now + TOKEN_LIFETIME,
"aud": "appstoreconnect-v1"
}
ecdsa_key = OpenSSL::PKey::EC.new IO.read AUTH_KEY_PATH
return JWT.encode payload, ecdsa_key, "ES256", header
end
def request_api(method, uri_string, request_body = nil)
uri = URI(uri_string)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = { "Content-Type" => "application/json", "Authorization" => "Bearer #{$token}" }
request = HTTP_METHODS[method].new(uri.path, headers)
if request_body != nil then
request.body = request_body.to_json
end
response = http.request(request)
case response
when Net::HTTPSuccess
return JSON.parse(response.body)
else
return nil
end
end
def make_new_version(version)
request_body = {
"data": {
"type": "appStoreVersions",
"attributes": {
"platform": "IOS",
"versionString": version,
"releaseType": "MANUAL"
},
"relationships": {
"app": {
"data": {
"type": "apps",
"id": APP_ID
}
}
}
}
}
result = request_api(:post, "https://api.appstoreconnect.apple.com/v1/appStoreVersions", request_body)
if result == nil then
puts "Failed to create new version: #{VERSION}"
return nil
else
puts "Created new version: #{VERSION}"
return result['data']['id']
end
end
def fetch_latest_version_id()
result = request_api(:get, "https://api.appstoreconnect.apple.com/v1/apps/#{APP_ID}/appStoreVersions")
version_id = result == nil ? nil : result['data'][0]['id']
if version_id == nil then
puts "Failed to fetch latest version id"
else
version_string = result['data'][0]['attributes']['versionString']
puts "Fetched latest version id: #{version_id} (#{version_string})"
end
return version_id
end
def fetch_localizations(version_id)
result = request_api(:get, "https://api.appstoreconnect.apple.com/v1/appStoreVersions/#{version_id}/appStoreVersionLocalizations")
if result == nil then
puts "Failed to fetch localizations"
return nil
end
puts "Fetched localizations"
return result['data'].map do |localization|
{ 'id' => localization['id'], 'locale' => localization['attributes']['locale'] }
end
end
def read_whats_new_files
files = Dir.glob("./whats_new/**/*")
contents = {}
return files.map {|file|
{ File.basename(file, ".*") => File.read(file) }
}.reduce({}, :merge)
end
def update_localization(localization_id, whats_new, locale)
request_body = {
"data": {
"id": localization_id,
"type": "appStoreVersionLocalizations",
"attributes": {
"whatsNew": whats_new
}
}
}
result = request_api(:patch, "https://api.appstoreconnect.apple.com/v1/appStoreVersionLocalizations/#{localization_id}", request_body)
if result == nil then
puts "Failed to update localization: #{locale}"
else
puts "Updated localization: #{locale}"
end
return result
end
# make token
$token = make_token
# make new version
# (don't exit if failed, because version may already be created and we can continue to update localizations)
version_id = nil
if not FETCH_LOCALES then
version_id = make_new_version(VERSION)
end
# fetch latest version id
if version_id == nil then
version_id = fetch_latest_version_id()
end
exit if version_id == nil
# fetch localizations
localizations = fetch_localizations(version_id)
exit if localizations == nil
if FETCH_LOCALES then
# print locales
puts "Locales:"
puts localizations.map { |localization| localization['locale'] }
exit
else
# update localizations
read_whats_new_files().each do |locale, whats_new|
localization = localizations.find { |localization| localization['locale'] == locale }
if localization != nil then
update_localization(localization['id'], whats_new, locale)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment