Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 1 addition & 42 deletions .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,50 +130,9 @@ jobs:
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Prepare Play Store credentials
env:
PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }}
run: |
bundle exec ruby -rbase64 -rjson -e '
raw = ENV.fetch("PLAY_STORE_JSON_KEY", "").strip
abort("PLAY_STORE_JSON_KEY is empty") if raw.empty?

candidates = [raw]
begin
decoded = Base64.strict_decode64(raw.gsub(/\s+/, "")).strip
candidates << decoded unless decoded.empty?
rescue ArgumentError
nil
end

json = candidates.lazy.map do |candidate|
begin
parsed = JSON.parse(candidate)
if parsed.is_a?(String)
nested = JSON.parse(parsed)
[parsed, nested]
else
[candidate, parsed]
end
rescue JSON::ParserError
nil
end
end.find do |entry|
next false unless entry

parsed = entry[1]
parsed.is_a?(Hash) &&
parsed["type"] == "service_account" &&
!parsed["client_email"].to_s.empty? &&
!parsed["private_key"].to_s.empty?
end&.first

abort("PLAY_STORE_JSON_KEY must contain raw service account JSON or its base64-encoded contents") unless json
File.write("play-store-key.json", json + "\n")
'
- name: Deploy to Google Play Store via Fastlane
env:
PLAY_STORE_JSON_KEY_PATH: ${{ github.workspace }}/play-store-key.json
PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }}
run: bundle exec fastlane android deploy track:internal # default to internal deploy, change this when needed

success:
Expand Down
64 changes: 53 additions & 11 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'base64'
require 'json'
require 'tmpdir'

def parse_json_document(value)
JSON.parse(value)
Expand All @@ -14,31 +15,72 @@ def play_store_service_account?(parsed)
!parsed['private_key'].to_s.empty?
end

def normalize_play_store_json(raw_value)
candidates = [raw_value.to_s.strip].reject(&:empty?)
def add_play_store_json_candidate(candidates, value)
candidate = value.to_s.strip
candidate = candidate.sub(/\A(?:export\s+)?PLAY_STORE_JSON_KEY(?:_DATA)?\s*=\s*/, '').strip

variants = [candidate]
if (candidate.start_with?('"') && candidate.end_with?('"')) ||
(candidate.start_with?("'") && candidate.end_with?("'"))
variants << candidate[1...-1].strip
end

variants.each do |variant|
candidates << variant unless variant.empty? || candidates.include?(variant)
end
end

begin
decoded = Base64.strict_decode64(raw_value.to_s.gsub(/\s+/, ''))
candidates << decoded.strip unless decoded.to_s.strip.empty?
rescue ArgumentError
nil
def base64_decode_play_store_json_candidate(candidate)
compact = candidate.to_s.gsub(/\s+/, '')
return nil if compact.empty?

padded = compact + ('=' * ((4 - compact.length % 4) % 4))

[compact, padded].uniq.each do |value|
begin
return Base64.strict_decode64(value)
rescue ArgumentError
begin
return Base64.urlsafe_decode64(value)
rescue ArgumentError
nil
end
end
end

nil
end

def normalize_play_store_json(raw_value)
candidates = []
add_play_store_json_candidate(candidates, raw_value)

candidates.each do |candidate|
parsed = parse_json_document(candidate)
return candidate if play_store_service_account?(parsed)
return JSON.generate(parsed) if play_store_service_account?(parsed)

if parsed.is_a?(String)
nested = parse_json_document(parsed)
return parsed if play_store_service_account?(nested)
add_play_store_json_candidate(candidates, parsed)
elsif parsed.is_a?(Hash)
%w[PLAY_STORE_JSON_KEY PLAY_STORE_JSON_KEY_DATA json_key_data json_key].each do |key|
add_play_store_json_candidate(candidates, parsed[key]) if parsed.key?(key)
end
end

add_play_store_json_candidate(candidates, base64_decode_play_store_json_candidate(candidate))
end

FastlaneCore::UI.user_error!(
"PLAY_STORE_JSON_KEY / PLAY_STORE_JSON_KEY_DATA must contain the Google Play service account JSON or its base64-encoded contents."
)
end

def write_play_store_json_key(raw_value)
key_path = File.join(Dir.tmpdir, "echo-play-store-key-#{Process.pid}.json")
File.write(key_path, normalize_play_store_json(raw_value) + "\n")
key_path
end

def play_store_credentials_options
key_path = ENV['PLAY_STORE_JSON_KEY_PATH'].to_s.strip
return { json_key: key_path } unless key_path.empty?
Expand All @@ -50,7 +92,7 @@ def play_store_credentials_options
)
end

{ json_key_data: normalize_play_store_json(raw_key) }
{ json_key: write_play_store_json_key(raw_key) }
end

platform :android do
Expand Down