Skip to content

The provided entity includes an unknown attribute - 'templateName' is not an attribute on the resource 'profiles' - /data/attributes/templateName #29498

@redreceipt

Description

@redreceipt

New Issue Checklist

Issue Description

Looks like Apple removed templateName from the API call

https://developer.apple.com/documentation/appstoreconnectapi/profilecreaterequest/data-data.dictionary/attributes-data.dictionary

Command executed

fastlane match(type: appstore)

Complete output when running fastlane, including the stack trace and command used
Image

Environment

✅ fastlane environment ✅

Stack

Key Value
OS 15.3.2
Ruby 3.4.2
Bundler? false
Git git version 2.39.5 (Apple Git-154)
Installation Source /opt/homebrew/Cellar/fastlane/2.227.0/libexec/bin/fastlane
Host macOS 15.3.2 (24D81)
Ruby Lib Dir /opt/homebrew/Cellar/ruby/3.4.2/lib
OpenSSL Version OpenSSL 3.4.1 11 Feb 2025
Is contained false
Is homebrew true
Is installed via Fabric.app false
Xcode Path /Applications/Xcode.app/Contents/Developer/
Xcode Version 16.2
Swift Version 6.0.3

System Locale

Variable Value
LANG en_US.UTF-8
LC_ALL
LANGUAGE

fastlane files:

`./fastlane/Fastfile`
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

require 'net/http'
require 'uri'
require 'json'

def update_config(key, value)
  church_header = ENV['CHURCH_HEADER']
  uri = URI.parse("https://cluster.apollos.app/api/config/#{church_header}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true if uri.scheme == 'https'

  request = Net::HTTP::Post.new(uri.request_uri)
  request['Content-Type'] = 'application/json'
  request['x-api-key'] = ENV['APOLLOS_API_KEY']

  request.body = { key: key, value: value }.to_json

  response = http.request(request)
  return unless response.code != '200'

  UI.user_error!("Failed to update config: #{response.code} #{response.message}")
end

def modify_env(key, value)
  env_file = '../.env'
  variable_found = false

  # Read the .env file into an array of lines
  env_lines = File.readlines(env_file)

  # Iterate through each line to find and modify the variable
  env_lines.map! do |line|
    if line.start_with?("#{key}=")
      variable_found = true
      "#{key}=#{value}\n" # Modify the existing variable
    else
      line
    end
  end

  # If the variable was not found, add it to the end of the file
  env_lines << "#{key}=#{value}\n" unless variable_found

  # Write the updated lines back to the .env file
  File.open(env_file, 'w') do |f|
    f.puts(env_lines)
  end
end

platform :ios do
  desc 'Sets up new app'
  lane :setup do
    produce(platforms: %w[ios tvos],
            # TODO: make sure this can work retroactively for Apps that already exist
            # or else we'll have to run seperate enable_services sh commands for existing apps
            # see deprecated ./scripts/setup.sh for details
            enable_services: { push_notification: 'on', app_group: 'on', associated_domains: 'on' })
    produce(app_identifier: "#{ENV['PRODUCE_APP_IDENTIFIER']}.OneSignalNotificationServiceExtension",
            app_name: 'Apollos Onesignal Extension', skip_itc: true, enable_services: { app_group: 'on' })
    # I wish Fastlane had a native way to do this :/
    sh("fastlane produce group -g \"group.#{ENV['PRODUCE_APP_IDENTIFIER']}.onesignal\" -n \"OneSignal Group\"")
    sh("fastlane produce associate_group \"group.#{ENV['PRODUCE_APP_IDENTIFIER']}.onesignal\"")
    sh("fastlane produce associate_group -a \"#{ENV['PRODUCE_APP_IDENTIFIER']}.OneSignalNotificationServiceExtension\" \"group.#{ENV['PRODUCE_APP_IDENTIFIER']}.onesignal\"")
    privacy
    certs
    notifications
  end

  desc 'Sets up Onesignal App'
  lane :notifications do
    pem(output_path: './fastlane', pem_name: 'apollos', force: true)
    onesignal(apns_p12: './fastlane/apollos.p12')
    app_id = lane_context[SharedValues::ONE_SIGNAL_APP_ID]
    modify_env('ONE_SIGNAL_APP_ID', app_id)
    update_config('ONE_SIGNAL.APP_ID', app_id)

    # TODO: OneSignal API changed and broke this
    auth_key = lane_context[SharedValues::ONE_SIGNAL_APP_AUTH_KEY]
    UI.user_error!('Failed to get auth key, set ONE_SIGNAL.REST_KEY manually!') if auth_key.nil? || auth_key.empty?
    update_config('ONE_SIGNAL.REST_KEY', auth_key)
  end

  desc 'Generates new certs/profiles and adds them to Match repo'
  lane :certs do
    match(type: 'appstore')
  end

  desc 'Renews expired certs/profiles and adds them to Match repo'
  lane :renew_certs do
    begin
      match(type: 'appstore', readonly: true, verbose: true)
    rescue StandardError => e
      UI.message(e)
    end
    match_nuke(type: 'appstore')
    match(type: 'appstore')
  end

  desc 'Prepares for running gym deploy'
  lane :prepare_gym do
    type = 'appstore'
    match(type: type, readonly: true)
    update_code_signing_settings(
      path: Dir.glob('ios/*.xcodeproj', base: '../').first,
      code_sign_identity: 'iPhone Distribution'
    )
    update_project_provisioning(
      xcodeproj: Dir.glob('ios/*.xcodeproj', base: '../').first,
      profile: ENV["sigh_#{ENV['FASTLANE_APP_IDENTIFIER']}_#{type}_profile-path"]
    )
    update_project_provisioning(
      xcodeproj: Dir.glob('ios/*.xcodeproj', base: '../').first,
      profile: ENV["sigh_#{ENV['FASTLANE_APP_IDENTIFIER']}.OneSignalNotificationServiceExtension_#{type}_profile-path"],
      target_filter: '.*OneSignal.*'
    )
  end

  desc 'Sets app privacy details'
  lane :privacy do
    upload_app_privacy_details_to_app_store(json_path: './fastlane/app-privacy-details.json')
  end

  desc 'Deploys a build to internal testflight or pushes internal to open beta or production'
  lane :deploy do
    track = ENV['TRACK'] || 'internal'
    UI.user_error!('Production deployment not ready!') if track == 'production' and ENV['PRODUCTION_READY'] != 'true'
    if ENV['DESIRED_VERSION'] && !ENV['DESIRED_VERSION'].empty?
      version = ENV['DESIRED_VERSION']
    else
      begin
        app_store_build_number
        live_version = lane_context[SharedValues::LATEST_VERSION]
        UI.message("Latest live version: #{live_version}")
      rescue StandardError => e
        UI.user_error!("Failed to get live version from App Store: #{e}") if e.to_s.include? 'agreement'
        UI.message("Failed to get live version from App Store: #{e}")
        live_version = nil
      end
      if live_version
        UI.message('Incrementing live version')
        increment_version_number(version_number: live_version)
        version = increment_version_number
      else
        version = '1.0.0'
      end
    end
    UI.message("Deploying version: #{version}")

    setup_ci
    UI.user_error!('ONE_SIGNAL_APP_ID is not set') if ENV['ONE_SIGNAL_APP_ID'].nil? || ENV['ONE_SIGNAL_APP_ID'].empty?
    prepare_gym
    increment_build_number(build_number: Time.now.to_i.to_s)
    increment_version_number(version_number: version)
    gym(export_method: 'app-store')

    if version == '1.0.0'
      UI.message('Set pricing, press enter...')
      $stdin.gets
    end

    if track == 'internal'
      testflight(skip_waiting_for_build_processing: false)
    elsif track == 'beta'
      testflight(
        distribute_external: true,
        groups: 'Beta Testers',
        app_platform: 'ios'
      )
    elsif track == 'production'
      deliver(
        overwrite_screenshots: true,
        submit_for_review: true,
        automatic_release: false,
        submission_information: {
          "add_id_info_uses_idfa": false,
          "content_rights_contains_third_party_content": false
        },
        reject_if_possible: true,
        run_precheck_before_submit: false,
        platform: 'ios',
        # https://github.com/fastlane/fastlane/issues/21819
        # price_tier: 0, This one is still manual for now
        app_rating_config_path: './fastlane/app-rating-config.json',
        force: true
      )
    end
  end
end

platform :android do
  desc 'Sets up new app'
  lane :setup do
    notifications
  end

  desc 'Sets up Onesignal App'
  lane :notifications do
    onesignal(fcm_json: './fastlane/fcm.json')
    app_id = lane_context[SharedValues::ONE_SIGNAL_APP_ID]
    update_config('ONE_SIGNAL.APP_ID', app_id)
    modify_env('ONE_SIGNAL_APP_ID', app_id)

    # TODO: OneSignal API changed and broke this
    auth_key = lane_context[SharedValues::ONE_SIGNAL_APP_AUTH_KEY]
    UI.user_error!('Failed to get auth key, set ONE_SIGNAL.REST_KEY manually!') if auth_key.nil? || auth_key.empty?
    update_config('ONE_SIGNAL.REST_KEY', auth_key)
  end

  desc 'Deploy an Android app'
  lane :deploy do
    validate_play_store_json_key
    track = ENV['TRACK'] || 'internal'
    # Set the Android version offset if it's not already set
    build_code_offset = ENV['ANDROID_BUILD_CODE_OFFSET'] || 0

    if ENV['DESIRED_VERSION'] && !ENV['DESIRED_VERSION'].empty?
      version = ENV['DESIRED_VERSION']
    else
      begin
        live_version = google_play_track_release_names[0]
        UI.message("Latest live version: #{live_version}")
      rescue StandardError => e
        UI.user_error!("Failed to get live version from Google Play: #{e}") if e.to_s.include? 'permission'
        UI.message("Failed to get live version from Google Play: #{e}")
        live_version = nil
      end

      if live_version
        semver_regex = /(\d+(?:\.\d+){0,2})/
        UI.message('Incrementing live version')
        versions = live_version.scan(semver_regex).flatten
        UI.user_error!('Version is not in the correct format!') unless versions
        # find semver version and increment patch
        # if version is 4 we want to increment to 4.0.1
        # if version is 4.1 we want to increment to 4.1.1
        # so the last two sections should be optional when finding the regex
        #
        # if we find two matches, we want to take the
        # first one closest to a real semver
        # it could be 100 (1.0.0) or 1.0.0 (100)
        semver_version = versions.find { |v| v.split('.').length == 3 }
        unless semver_version
          major_minor_version = versions.find { |v| v.split('.').length == 2 }
          semver_version = major_minor_version + '.0' if major_minor_version
        end
        semver_version ||= versions[0] + '.0.0'

        # now increment the patch
        components = semver_version.split('.').map(&:to_i)
        components[-1] += 1
        version = components.join('.')
      else
        UI.user_error!('Failed to get live version from Google Play. use DESIRED_VERSION=1.0.0 to create a new app manually.')
      end
    end
    UI.message("Deploying version: #{version}")
    # TODO: put back when onesignal API bug is fixed
    # notifications
    if version == '1.0.0'
      UI.message('Upload FCM to OneSignal, press enter...')
      $stdin.gets
    end

    date_in_hrs = Time.now.to_i / 3600
    mobile_version_offset = 1_000_000

    codes_to_keep = []
    if version != '1.0.0'
      begin
        earliest = Time.new(2020, 1, 1).to_i / 3600
        version_codes = google_play_track_version_codes(track: track)
        codes_as_timestamps = version_codes.map { |code| code.to_i - build_code_offset.to_i - mobile_version_offset }
        non_apollos_mobile_codes = codes_as_timestamps.select do |timestamp|
          timestamp < earliest or timestamp > date_in_hrs
        end
        codes_to_keep = non_apollos_mobile_codes.map do |timestamp|
          timestamp + build_code_offset.to_i + mobile_version_offset
        end
      rescue StandardError => e
        UI.user_error!("Failed to get version codes: #{e}") if e.to_s.include? 'permission'
        UI.message("Failed to get version codes: #{e}")
        codes_to_keep = []
      end
      UI.message("Keeping version codes: #{codes_to_keep}")
    end

    version_code = date_in_hrs + mobile_version_offset + build_code_offset.to_i
    build_gradle_file = '../android/app/build.gradle'
    gradle_file = File.read(build_gradle_file)
    gradle_file = gradle_file.gsub(/versionCode \d+\s*$/, "versionCode #{version_code}")
    gradle_file = gradle_file.gsub(/versionName ".*"\s*$/, "versionName \"#{version}\"")
    File.open(build_gradle_file, 'w') { |file| file.puts gradle_file }

    # Build the Android App
    gradle(task: 'clean', project_dir: 'android')
    gradle(
      task: 'bundle',
      build_type: 'Release',
      project_dir: 'android',
      properties: {
        'android.injected.signing.store.file' => ENV['KEYSTORE_FILE'],
        'android.injected.signing.store.password' => ENV['KEYSTORE_PASSWORD'],
        'android.injected.signing.key.alias' => ENV['KEY_ALIAS'],
        'android.injected.signing.key.password' => ENV['KEY_PASSWORD']
      }
    )

    UI.user_error!('Production deployment not ready!') if track == 'production' and ENV['PRODUCTION_READY'] != 'true'
    if version == '1.0.0'
      UI.message('Upload AAB, finish dashboard steps, promote to production, press enter...')
      loop do
        $stdin.gets
        begin
          google_play_track_version_codes(track: track)
        rescue StandardError => e
          UI.message("#{e}")
          UI.message('Try again and press enter...')
          next
        end
        break
      end
    end
    supply(
      track: track,
      version_codes_to_retain: codes_to_keep,
      skip_upload_aab: version == '1.0.0',
      skip_upload_changelogs: version == '1.0.0',
      changes_not_sent_for_review: true,
      aab: 'android/app/build/outputs/bundle/release/app-release.aab'
    )
  end
end

No Appfile found

fastlane gems

Gem Version Update-Status
fastlane 2.227.0 ✅ Up-To-Date

Loaded fastlane plugins:

No plugins Loaded

Loaded gems
Gem Version
error_highlight 0.7.0
did_you_mean 2.0.0
syntax_suggest 2.0.2
public_suffix 6.0.1
addressable 2.8.7
artifactory 3.0.17
aws-eventstream 1.3.2
aws-partitions 1.1065.0
aws-sigv4 1.11.0
base64 0.2.0
jmespath 1.6.2
aws-sdk-core 3.220.1
aws-sdk-kms 1.99.0
aws-sdk-s3 1.182.0
babosa 1.0.4
bundler 2.6.3
rexml 3.4.1
nkf 0.2.0
CFPropertyList 3.0.7
colored 1.2
highline 2.0.3
commander 4.6.0
dotenv 2.8.1
emoji_regex 3.2.3
excon 0.112.0
faraday-em_http 1.0.0
faraday-em_synchrony 1.0.0
faraday-excon 1.1.0
faraday-httpclient 1.0.1
multipart-post 2.4.1
faraday-multipart 1.1.0
faraday-net_http 1.0.2
faraday-net_http_persistent 1.2.0
faraday-patron 1.0.0
faraday-rack 1.0.0
faraday-retry 1.0.3
ruby2_keywords 0.0.5
faraday 1.10.4
faraday_middleware 1.2.1
domain_name 0.6.20240107
http-cookie 1.0.8
faraday-cookie_jar 0.0.7
fastimage 2.4.0
sysrandom 1.0.5
fastlane-sirp 1.0.0
gh_inspector 1.1.3
uber 0.1.0
declarative 0.0.20
trailblazer-option 0.1.2
representable 3.2.0
retriable 3.1.2
mini_mime 1.1.5
jwt 2.10.1
multi_json 1.15.0
os 1.1.4
signet 0.19.0
googleauth 1.8.1
mutex_m 0.3.0
httpclient 2.9.0
google-apis-core 0.11.3
google-apis-androidpublisher_v3 0.54.0
google-apis-playcustomapp_v1 0.13.0
google-cloud-env 1.6.0
google-cloud-errors 1.5.0
google-cloud-core 1.8.0
google-apis-iamcredentials_v1 0.17.0
google-apis-storage_v1 0.31.0
rake 13.2.1
digest-crc 0.7.0
google-cloud-storage 1.47.0
json 2.9.1
mini_magick 4.13.2
naturally 2.2.1
optparse 0.6.0
plist 3.7.2
rubyzip 2.4.1
security 0.1.5
simctl 1.6.10
terminal-notifier 2.0.0
unicode-display_width 2.6.0
terminal-table 3.0.2
tty-screen 0.8.2
tty-cursor 0.7.1
tty-spinner 0.9.3
word_wrap 1.0.0
atomos 0.1.3
claide 1.1.0
colored2 3.1.2
nanaimo 0.4.0
xcodeproj 1.27.0
rouge 3.28.0
xcpretty 0.4.0
xcpretty-travis-formatter 1.0.1
set 1.1.1
forwardable 1.3.3
logger 1.6.4
pathname 0.4.0
shellwords 0.2.2
cgi 0.4.1
date 3.4.1
timeout 0.4.3
stringio 3.1.2
securerandom 0.4.1
uri 1.0.2
ipaddr 1.2.7
openssl 3.3.0
digest 3.2.0
io-nonblock 0.3.1
zlib 3.2.1
resolv 0.6.0
io-wait 0.3.1
time 0.4.1
open-uri 0.5.0
net-http 0.6.0
net-protocol 0.2.2
english 0.8.0
erb 4.0.4
strscan 3.1.2
abbrev 0.1.2
io-console 0.8.0
tempfile 0.3.1
delegate 0.4.0
fileutils 1.7.3
tmpdir 0.3.1
singleton 0.3.0
open3 0.2.1
prettyprint 0.2.0
pp 0.6.2
find 0.2.0
ostruct 0.6.1
yaml 0.4.0
psych 5.2.2

generated on: 2025-03-18

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions