match+gym not automatically setting up provisioning profiles
New Issue Checklist
- [x] Updated fastlane to the latest version
- [x] I read the Contribution Guidelines
- [x] I read docs.fastlane.tools
- [x] I searched for existing GitHub issues
Issue Description
I'm trying to set up my pipeline to use fastlane match+gym to build my app, but consistently receive an error stating
error: "<TARGET NAME REDACTED>" requires a provisioning profile with the App Groups feature. Select a provisioning profile in the Signing & Capabilities editor. (in target '<TARGET NAME REDACTED>' from project '<PROJECT NAME REDACTED>')
I was expecting match to automatically set all of that up. When I go into my xcode project and manually set the provisioning profile for my targets to the profiles installed by match, and then run gym, it works as expected and successfully builds and archives the app. If I don't manually do that, it fails with the message above.
Based on http://docs.fastlane.tools/codesigning/xcode-project/, it seems like this might be intended behaviour. Would you be open to me creating a pull request to go through the provisioning profiles from match and update the targets via fastlane before running gym? I think it would be a much cleaner experience to be able to just say
lane :appstore-build do
match(type: 'appstore')
gym(export_method: 'app-store')
end
lane :enterprise-build do
match(type: 'enterprise')
gym(export_method: 'enterprise')
end
and have that work without needing to manually update provisioning profiles in xcode between running the two lanes.
I think I have pretty much everything I need to get that working and create a PR, except for the ability to get the certificate name (in order to update the codesigning identity) from match. Would appreciate any support on figuring out how to get that value from match, but if we can do that, then I would be happy to update the actions and create a PR to set that all up automatically without needing any intervention.
It seems like you have not included the output of fastlane env
To make it easier for us help you resolve this issue, please update the issue to include the output of fastlane env :+1:
I know that tagging you is a bit rude, so apologies in advance, but @joshdholtz you've been very helpful with my PRs in the past so would love to hear if this is something you would be interested in getting added to fastlane, and if you could help me with getting the certificate name. Thanks!
I am also facing exact same issue. Is your issue resloved? any recommendation how to solve this issue.? Can any one please help? MyInsuranceInfo
This works really well for us, thank you! Facing same issue here. Help is appreciated. MyCoverageInfo.com
When I quicklook the profiles I see this, and the value next to "Name" under certificates is the value that I want.

FastlaneCore::ProvisioningProfile doesn't seem to populate this value. I do see DeveloperCertificates as a key, but that references an array of StringIOs. When I run lines = profile['DeveloperCertificates'][0].readlines I get what looks like some encoded strings but haven't been able to decrypt those. I do see "iPhone Distribution: <Company Name redacted>." in lines[4], but no clue how to reliably parse that out :/
If you know what format those are and if there's a way to reliably parse those it'd be super helpful
Hi @tejassharma96 this is a really nice idea - having a logic to automatically setup profile in the project based on match result would probably make it easier to use fastlane.
As you noticed though, leaving a decision about code signing for the users looks like an intended behaviour by design. I have a feeling that such a functionality should be opt-in, and I'm thinking if it shouldn't be turned off by default and enabled with an option switch in gym. Otherwise it could potentially be a breaking change and cause issues for the current users after update to newer version of fastlane. What do you think?
And as a side note, currently code signing settings in the project can be either handled manually in Xcode or changed with action http://docs.fastlane.tools/actions/update_project_provisioning/#update_project_provisioning
just between match and gym call. Match adds environment variable with path to provisioning profile and it could be used in update_project_provisioning to set the profile. If you also need to change team, you could use update_project_team action.
right I was thinking I could add a update_targets_automatically flag to match that defaults to false. I wrote a custom action that achieves this and was hoping we could just get it into fastlane instead, since it definitely feels like something fastlane could/should support. I'd argue that it should be in match over gym since just running match will automatically set up code signing for your xcode project/workspace and then you can build in xcode too vs just via gym. I'd also love to get https://github.com/fastlane/fastlane/pull/20187 merged in to support this. I'd be happy to create a draft PR of how it might look directly integrated into match once that gets merged.
I can't link to my action since it's in an internal repo, but I've copied it below:
module Fastlane
module Actions
class EnhancedMatchAction < Action
INFOPLIST_FILE_KEY = "INFOPLIST_FILE"
BUNDLE_ID_KEY = "CFBundleIdentifier"
TEAM_ID_KEY = "DEVELOPMENT_TEAM"
CODE_SIGN_IDENTITY_KEY = "CODE_SIGN_IDENTITY"
PROFILE_NAME_KEY = "PROVISIONING_PROFILE_SPECIFIER"
CODE_SIGN_STYLE_KEY = "CODE_SIGN_STYLE"
CODE_SIGN_STYLE_VALUE = "Manual"
CERTIFICATE_DATA_KEY = "DeveloperCertificates"
CERTIFICATE_NAME_KEY = "CN"
def self.run(params)
other_action.match(self.match_options(params).dup)
if params[:update_targets_automatically]
mapping = Actions.lane_context[SharedValues::MATCH_PROVISIONING_PROFILE_MAPPING]
unless mapping
UI.user_error!("Could not load the provisioning profile mapping from match")
return
end
self.update_targets_automatically(params, mapping)
end
end
def self.description
"Enhanced match"
end
def self.authors
["Tejas Sharma"]
end
def self.details
"Runs fastlane match and uses the provisioning profile mapping to automatically update the targets "\
"in your xcodeproj files. You must provide the team id and code sign identity manually"\
end
def self.available_options
Fastlane::Actions::MatchAction.available_options + [
FastlaneCore::ConfigItem.new(key: :build_configurations,
env_name: "ENHANCED_MATCH_BUILD_CONFIGURATIONS",
optional: true,
type: Array,
description: "Specify build_configurations you want to update signing for. (default to all configurations)"),
FastlaneCore::ConfigItem.new(key: :code_sign_identity,
env_name: "ENHANCED_MATCH_CODE_SIGN_IDENTITY",
type: String,
description: "Code signing identity type (iPhone Developer, iPhone Distribution). If you don't provide a value for this, "\
"the action will attempt to parse the value from your provisioning profile",
optional: true),
FastlaneCore::ConfigItem.new(key: :update_targets_automatically,
env_name: "ENHANCED_MATCH_UPDATE_TARGETS",
description: "Specify whether the action should automatically update provisioning profiles for your targets."\
"You must pass in values for team_id and code_sign_identity when setting this to true",
default_value: false,
type: Boolean,
optional: false)
]
end
def self.is_supported?(platform)
[:ios, :mac].include?(platform)
end
def self.match_options(params)
Fastlane::Actions::MatchAction.available_options.map { |i| [i.key, params[i.key]] }.to_h.compact
end
def self.update_targets_automatically(params, mapping)
Helper::XcodeprojHelper.get_all_xcodeprojects.each do |proj|
update_signing_for_targets(params, proj, mapping)
end
end
# rubocop:disable Metrics/PerceivedComplexity
def self.update_signing_for_targets(params, project, mapping)
project.targets.each do |target|
target.build_configurations.each do |config|
if params[:build_configurations] && !params[:build_configurations].include?(config.name)
UI.verbose("Skipping #{config.name} not selected (#{params[:build_configurations].join(',')})")
next
end
bundle_id = self.get_bundle_id(config)
unless bundle_id
UI.verbose("Skipping #{config.name} for #{target.name}, no bundle id")
next
end
unless mapping.key?(bundle_id)
UI.verbose("Skipping #{config.name} for #{target.name}, bundle id #{bundle_id} not included in match mapping")
next
end
team_id = params[:team_id] || get_team_id(params, bundle_id)
unless team_id
UI.user_error!("No value provided for :team_id, and we were unable to automatically detect a value based on the provisioning profile.")
return nil
end
code_sign_identity = params[:code_sign_identity] || self.get_code_sign_identity(params, bundle_id)
unless code_sign_identity
UI.user_error!("No value provided for :code_sign_identity, and we were unable to automatically detect a value based on the provisioning profile.")
return nil
end
set_build_setting(config, CODE_SIGN_STYLE_KEY, CODE_SIGN_STYLE_VALUE)
UI.verbose("Set Code Sign Style to: Manual for target: #{target.name} for build configuration: #{config.name}")
set_build_setting(config, CODE_SIGN_IDENTITY_KEY, code_sign_identity)
UI.verbose("Set Code Sign Identity to: #{code_sign_identity} for target: #{target.name} for build configuration: #{config.name}")
set_build_setting(config, TEAM_ID_KEY, team_id)
UI.verbose("Set Team ID to: #{params[:team_id]} for target: #{target.name} for build configuration: #{config.name}")
set_build_setting(config, PROFILE_NAME_KEY, mapping[bundle_id])
UI.verbose("Set Provisioning Profile Name to: #{mapping[bundle_id]} for target: #{target.name} for build configuration: #{config.name}")
UI.important("Updated code signing values for target: #{target.name} for build configuration: #{config.name}")
end
end
project.save
end
# rubocop:enable Metrics/PerceivedComplexity
def self.set_build_setting(configuration, name, value)
# Iterate over any keys that start with this name
# This will also set keys that have filtering like [sdk=iphoneos*]
keys = configuration.build_settings.keys.select { |key| key.to_s.match(/#{name}.*/) }
keys.each do |key|
configuration.build_settings[key] = value
end
# Explicitly set the key with value if keys don't exist
configuration.build_settings[name] = value
end
def self.get_bundle_id(build_configuration)
infoplist_path = build_configuration.build_settings[INFOPLIST_FILE_KEY]
unless infoplist_path && File.exist?(infoplist_path)
return nil
end
plist_data = Xcodeproj::Plist.read_from_path(infoplist_path)
return plist_data[BUNDLE_ID_KEY]
end
def self.get_team_id(params, bundle_id)
require 'match'
env_variable_name = Match::Utils.environment_variable_name_profile_name(app_identifier: bundle_id,
type: Match.profile_type_sym(params[:type]),
platform: params[:platform])
return ENV[env_variable_name]
end
def self.get_code_sign_identity(params, bundle_id)
require 'match'
require 'openssl'
env_variable_name = Match::Utils.environment_variable_name_profile_path(app_identifier: bundle_id,
type: Match.profile_type_sym(params[:type]),
platform: params[:platform])
path = ENV[env_variable_name]
unless path && File.exist?(path)
return nil
end
profile = FastlaneCore::ProvisioningProfile.parse(path)
cert = OpenSSL::X509::Certificate.new(profile[CERTIFICATE_DATA_KEY].first.string)
cert_info = cert.subject.to_s.gsub(/\s*subject=\s*/, "").tr("/", "\n")
values = cert_info.split("\n")
.map { |x| x.split(/=+/) if x.include?("=") }
.compact
.to_h
return values[CERTIFICATE_NAME_KEY]
end
end
end
end
hey @lucgrabowski apologies for the tag, but was hoping to follow up on this - is this something you might be interested in including in fastlane? ofc it wouldn't look exactly like this since I'd be able to integrate it better with internal fastlane stuff, but something similar.
getting eyes on https://github.com/fastlane/fastlane/pull/20187 as an intermediary (so I can update get_code_sign_identity above) would also be great
Hi @tejassharma96, I really like the idea. @joshdholtz, could you take a look at the discussion and the code in the comment above and say what you think about such an action?
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.
Please make sure to update to the latest fastlane version and check if that solves the issue. Let us know if that works for you by adding a comment :+1:
Friendly reminder: contributions are always welcome! Check out CONTRIBUTING.md for more information on how to help with fastlane and feel free to tackle this issue yourself :muscle:
This issue will be auto-closed if there is no reply within 1 month.
pls no close fastlane bot. @joshdholtz have you had a chance to take a look at this?
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.
Please make sure to update to the latest fastlane version and check if that solves the issue. Let us know if that works for you by adding a comment :+1:
Friendly reminder: contributions are always welcome! Check out CONTRIBUTING.md for more information on how to help with fastlane and feel free to tackle this issue yourself :muscle:
This issue will be auto-closed if there is no reply within 1 month.
is this just destined to be auto closed @lucgrabowski @joshdholtz ? I thought it was a cool idea đ
Ah sorry! This got lost in my notifications âšī¸
I love this idea and I think it would be a great action to have! I did something similar in a few of my projects in the past. I'm totally happy to accept a PR for this đ
awesome! glad to hear it :) I'll see if I can get something up this weekend!
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.
Please make sure to update to the latest fastlane version and check if that solves the issue. Let us know if that works for you by adding a comment :+1:
Friendly reminder: contributions are always welcome! Check out CONTRIBUTING.md for more information on how to help with fastlane and feel free to tackle this issue yourself :muscle:
This issue will be auto-closed if there is no reply within 1 month.
sshhhhhh bot, we have a pull request