diff --git a/scripts/testflight-testers.rb b/scripts/testflight-testers.rb new file mode 100755 index 0000000..ee6fe7e --- /dev/null +++ b/scripts/testflight-testers.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby +# Invite people to a TestFlight group. +# +# APPLE_EMAIL=you@example.com ruby scripts/testflight-testers.rb someone@example.com ... +# +# Addresses come from the command line rather than a file in the repo, because a list of testers is +# a list of people's email addresses and this repository is public. +# +# GROUP defaults to the external group, since the internal one only accepts people who already have +# an App Store Connect account on the team, which is a far bigger thing to hand out than a build. +begin + require "spaceship" +rescue LoadError + libexec = Dir["/opt/homebrew/Cellar/fastlane/*/libexec", "/usr/local/Cellar/fastlane/*/libexec"].max + abort "spaceship is not installed. `brew install fastlane` and rerun." unless libexec + ENV["GEM_PATH"] = [libexec, ENV["GEM_PATH"]].compact.join(":") + Gem.clear_paths + require "spaceship" +end + +BUNDLE_ID = ENV.fetch("BUNDLE_ID", "studio.margin.app") +GROUP = ENV.fetch("GROUP", "Public Beta") +ENV["FASTLANE_ITC_TEAM_ID"] = ENV.fetch("FASTLANE_ITC_TEAM_ID", "129377371") + +emails = ARGV.reject { |a| a.start_with?("-") } +abort "Usage: ruby scripts/testflight-testers.rb someone@example.com [more@example.com ...]" if emails.empty? + +Spaceship::ConnectAPI.login(ENV["APPLE_EMAIL"], nil, use_portal: false, use_tunes: true) + +app = Spaceship::ConnectAPI::App.find(BUNDLE_ID) +abort "No app for #{BUNDLE_ID}." unless app + +group = app.get_beta_groups.find { |g| g.name == GROUP } +abort "No group named #{GROUP.inspect}." unless group +puts "#{app.name}: #{group.name} (#{group.is_internal_group ? 'internal' : 'external'})" + +existing = Spaceship::ConnectAPI::BetaTester + .all(filter: { betaGroups: group.id }) + .map { |t| t.email.to_s.downcase } + +emails.each do |email| + if existing.include?(email.downcase) + puts " #{email} is already in this group" + next + end + + Spaceship::ConnectAPI.post_bulk_beta_tester_assignments( + beta_group_id: group.id, + beta_testers: [{ email: email }], + ) + puts " invited #{email}" +end + +puts +if group.is_internal_group + puts "Internal testers can install as soon as a build finishes processing." +else + puts "External testers get the invitation once beta app review passes." + puts "Anyone can also join through #{group.public_link}" if group.public_link +end