mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
feat: use fastlane sigh to manage signing profiles (#25089)
* feat: use fastlane sigh to manage signing profiles * remove unused secrects * remove unused fallback
This commit is contained in:
parent
1d6a9f6e80
commit
1f20b6471c
3 changed files with 75 additions and 63 deletions
35
.github/workflows/build-mobile.yml
vendored
35
.github/workflows/build-mobile.yml
vendored
|
|
@ -30,18 +30,6 @@ on:
|
||||||
required: true
|
required: true
|
||||||
IOS_CERTIFICATE_PASSWORD:
|
IOS_CERTIFICATE_PASSWORD:
|
||||||
required: true
|
required: true
|
||||||
IOS_PROVISIONING_PROFILE:
|
|
||||||
required: true
|
|
||||||
IOS_PROVISIONING_PROFILE_SHARE_EXTENSION:
|
|
||||||
required: true
|
|
||||||
IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION:
|
|
||||||
required: true
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE:
|
|
||||||
required: true
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION:
|
|
||||||
required: true
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION:
|
|
||||||
required: true
|
|
||||||
FASTLANE_TEAM_ID:
|
FASTLANE_TEAM_ID:
|
||||||
required: true
|
required: true
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
@ -240,35 +228,14 @@ jobs:
|
||||||
mkdir -p ~/.appstoreconnect/private_keys
|
mkdir -p ~/.appstoreconnect/private_keys
|
||||||
echo "$API_KEY_CONTENT" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${API_KEY_ID}.p8
|
echo "$API_KEY_CONTENT" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${API_KEY_ID}.p8
|
||||||
|
|
||||||
- name: Import Certificate and Provisioning Profiles
|
- name: Import Certificate
|
||||||
env:
|
env:
|
||||||
IOS_CERTIFICATE_P12: ${{ secrets.IOS_CERTIFICATE_P12 }}
|
IOS_CERTIFICATE_P12: ${{ secrets.IOS_CERTIFICATE_P12 }}
|
||||||
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
|
||||||
IOS_PROVISIONING_PROFILE: ${{ secrets.IOS_PROVISIONING_PROFILE }}
|
|
||||||
IOS_PROVISIONING_PROFILE_SHARE_EXTENSION: ${{ secrets.IOS_PROVISIONING_PROFILE_SHARE_EXTENSION }}
|
|
||||||
IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION: ${{ secrets.IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION }}
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE }}
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION }}
|
|
||||||
IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION }}
|
|
||||||
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
|
||||||
working-directory: ./mobile/ios
|
working-directory: ./mobile/ios
|
||||||
run: |
|
run: |
|
||||||
# Decode certificate
|
# Decode certificate
|
||||||
echo "$IOS_CERTIFICATE_P12" | base64 --decode > certificate.p12
|
echo "$IOS_CERTIFICATE_P12" | base64 --decode > certificate.p12
|
||||||
|
|
||||||
# Decode provisioning profiles based on environment
|
|
||||||
if [[ "$ENVIRONMENT" == "development" ]]; then
|
|
||||||
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE" | base64 --decode > profile_dev.mobileprovision
|
|
||||||
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE_SHARE_EXTENSION" | base64 --decode > profile_dev_share.mobileprovision
|
|
||||||
echo "$IOS_DEVELOPMENT_PROVISIONING_PROFILE_WIDGET_EXTENSION" | base64 --decode > profile_dev_widget.mobileprovision
|
|
||||||
ls -lh profile_dev*.mobileprovision
|
|
||||||
else
|
|
||||||
echo "$IOS_PROVISIONING_PROFILE" | base64 --decode > profile.mobileprovision
|
|
||||||
echo "$IOS_PROVISIONING_PROFILE_SHARE_EXTENSION" | base64 --decode > profile_share.mobileprovision
|
|
||||||
echo "$IOS_PROVISIONING_PROFILE_WIDGET_EXTENSION" | base64 --decode > profile_widget.mobileprovision
|
|
||||||
ls -lh profile*.mobileprovision
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create keychain and import certificate
|
- name: Create keychain and import certificate
|
||||||
env:
|
env:
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
KEYCHAIN_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
|
||||||
|
|
|
||||||
3
mobile/ios/.gitignore
vendored
3
mobile/ios/.gitignore
vendored
|
|
@ -33,4 +33,5 @@ Runner/GeneratedPluginRegistrant.*
|
||||||
!default.perspectivev3
|
!default.perspectivev3
|
||||||
|
|
||||||
fastlane/report.xml
|
fastlane/report.xml
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
|
certs/
|
||||||
|
|
@ -44,7 +44,7 @@ def get_version_from_pubspec
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper method to configure code signing for all targets
|
# Helper method to configure code signing for all targets
|
||||||
def configure_code_signing(bundle_id_suffix: "")
|
def configure_code_signing(bundle_id_suffix: "", profile_name_main:, profile_name_share:, profile_name_widget:)
|
||||||
bundle_suffix = bundle_id_suffix.empty? ? "" : ".#{bundle_id_suffix}"
|
bundle_suffix = bundle_id_suffix.empty? ? "" : ".#{bundle_id_suffix}"
|
||||||
|
|
||||||
# Runner (main app)
|
# Runner (main app)
|
||||||
|
|
@ -54,7 +54,7 @@ end
|
||||||
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
||||||
code_sign_identity: CODE_SIGN_IDENTITY,
|
code_sign_identity: CODE_SIGN_IDENTITY,
|
||||||
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}",
|
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}",
|
||||||
profile_name: "#{BASE_BUNDLE_ID}#{bundle_suffix} AppStore",
|
profile_name: profile_name_main,
|
||||||
targets: ["Runner"]
|
targets: ["Runner"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ end
|
||||||
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
||||||
code_sign_identity: CODE_SIGN_IDENTITY,
|
code_sign_identity: CODE_SIGN_IDENTITY,
|
||||||
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}.ShareExtension",
|
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}.ShareExtension",
|
||||||
profile_name: "#{BASE_BUNDLE_ID}#{bundle_suffix}.ShareExtension AppStore",
|
profile_name: profile_name_share,
|
||||||
targets: ["ShareExtension"]
|
targets: ["ShareExtension"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ end
|
||||||
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
team_id: ENV["FASTLANE_TEAM_ID"] || TEAM_ID,
|
||||||
code_sign_identity: CODE_SIGN_IDENTITY,
|
code_sign_identity: CODE_SIGN_IDENTITY,
|
||||||
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}.Widget",
|
bundle_identifier: "#{BASE_BUNDLE_ID}#{bundle_suffix}.Widget",
|
||||||
profile_name: "#{BASE_BUNDLE_ID}#{bundle_suffix}.Widget AppStore",
|
profile_name: profile_name_widget,
|
||||||
targets: ["WidgetExtension"]
|
targets: ["WidgetExtension"]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -87,7 +87,10 @@ end
|
||||||
bundle_id_suffix: "",
|
bundle_id_suffix: "",
|
||||||
configuration: "Release",
|
configuration: "Release",
|
||||||
distribute_external: true,
|
distribute_external: true,
|
||||||
version_number: nil
|
version_number: nil,
|
||||||
|
profile_name_main:,
|
||||||
|
profile_name_share:,
|
||||||
|
profile_name_widget:
|
||||||
)
|
)
|
||||||
bundle_suffix = bundle_id_suffix.empty? ? "" : ".#{bundle_id_suffix}"
|
bundle_suffix = bundle_id_suffix.empty? ? "" : ".#{bundle_id_suffix}"
|
||||||
app_identifier = "#{BASE_BUNDLE_ID}#{bundle_suffix}"
|
app_identifier = "#{BASE_BUNDLE_ID}#{bundle_suffix}"
|
||||||
|
|
@ -115,9 +118,9 @@ end
|
||||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
||||||
export_options: {
|
export_options: {
|
||||||
provisioningProfiles: {
|
provisioningProfiles: {
|
||||||
"#{app_identifier}" => "#{app_identifier} AppStore",
|
"#{app_identifier}" => profile_name_main,
|
||||||
"#{app_identifier}.ShareExtension" => "#{app_identifier}.ShareExtension AppStore",
|
"#{app_identifier}.ShareExtension" => profile_name_share,
|
||||||
"#{app_identifier}.Widget" => "#{app_identifier}.Widget AppStore"
|
"#{app_identifier}.Widget" => profile_name_widget
|
||||||
},
|
},
|
||||||
signingStyle: "manual",
|
signingStyle: "manual",
|
||||||
signingCertificate: CODE_SIGN_IDENTITY
|
signingCertificate: CODE_SIGN_IDENTITY
|
||||||
|
|
@ -136,20 +139,35 @@ end
|
||||||
lane :gha_testflight_dev do
|
lane :gha_testflight_dev do
|
||||||
api_key = get_api_key
|
api_key = get_api_key
|
||||||
|
|
||||||
# Install development provisioning profiles
|
# Download and install provisioning profiles from App Store Connect
|
||||||
install_provisioning_profile(path: "profile_dev.mobileprovision")
|
# Certificate is imported by GHA workflow into build.keychain
|
||||||
install_provisioning_profile(path: "profile_dev_share.mobileprovision")
|
# Capture profile names after each sigh call
|
||||||
install_provisioning_profile(path: "profile_dev_widget.mobileprovision")
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development", force: true)
|
||||||
|
main_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
# Configure code signing for dev bundle IDs
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development.ShareExtension", force: true)
|
||||||
configure_code_signing(bundle_id_suffix: "development")
|
share_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development.Widget", force: true)
|
||||||
|
widget_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
# Configure code signing for dev bundle IDs using the downloaded profile names
|
||||||
|
configure_code_signing(
|
||||||
|
bundle_id_suffix: "development",
|
||||||
|
profile_name_main: main_profile_name,
|
||||||
|
profile_name_share: share_profile_name,
|
||||||
|
profile_name_widget: widget_profile_name
|
||||||
|
)
|
||||||
|
|
||||||
# Build and upload
|
# Build and upload
|
||||||
build_and_upload(
|
build_and_upload(
|
||||||
api_key: api_key,
|
api_key: api_key,
|
||||||
bundle_id_suffix: "development",
|
bundle_id_suffix: "development",
|
||||||
configuration: "Profile",
|
configuration: "Profile",
|
||||||
distribute_external: false
|
distribute_external: false,
|
||||||
|
profile_name_main: main_profile_name,
|
||||||
|
profile_name_share: share_profile_name,
|
||||||
|
profile_name_widget: widget_profile_name
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -157,20 +175,33 @@ end
|
||||||
lane :gha_release_prod do
|
lane :gha_release_prod do
|
||||||
api_key = get_api_key
|
api_key = get_api_key
|
||||||
|
|
||||||
# Install provisioning profiles
|
# Download and install provisioning profiles from App Store Connect
|
||||||
install_provisioning_profile(path: "profile.mobileprovision")
|
# Certificate is imported by GHA workflow into build.keychain
|
||||||
install_provisioning_profile(path: "profile_share.mobileprovision")
|
sigh(api_key: api_key, app_identifier: BASE_BUNDLE_ID, force: true)
|
||||||
install_provisioning_profile(path: "profile_widget.mobileprovision")
|
main_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.ShareExtension", force: true)
|
||||||
|
share_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.Widget", force: true)
|
||||||
|
widget_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
|
||||||
# Configure code signing for production bundle IDs
|
# Configure code signing for production bundle IDs
|
||||||
configure_code_signing
|
configure_code_signing(
|
||||||
|
profile_name_main: main_profile_name,
|
||||||
|
profile_name_share: share_profile_name,
|
||||||
|
profile_name_widget: widget_profile_name
|
||||||
|
)
|
||||||
|
|
||||||
# Build and upload with version number
|
# Build and upload with version number
|
||||||
build_and_upload(
|
build_and_upload(
|
||||||
api_key: api_key,
|
api_key: api_key,
|
||||||
version_number: get_version_from_pubspec,
|
version_number: get_version_from_pubspec,
|
||||||
distribute_external: false,
|
distribute_external: false,
|
||||||
|
profile_name_main: main_profile_name,
|
||||||
|
profile_name_share: share_profile_name,
|
||||||
|
profile_name_widget: widget_profile_name
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -215,13 +246,26 @@ end
|
||||||
# Use the same build process as production, just skip the upload
|
# Use the same build process as production, just skip the upload
|
||||||
# This ensures PR builds validate the same way as production builds
|
# This ensures PR builds validate the same way as production builds
|
||||||
|
|
||||||
# Install provisioning profiles (use development profiles for PR builds)
|
api_key = get_api_key
|
||||||
install_provisioning_profile(path: "profile_dev.mobileprovision")
|
|
||||||
install_provisioning_profile(path: "profile_dev_share.mobileprovision")
|
# Download and install provisioning profiles from App Store Connect
|
||||||
install_provisioning_profile(path: "profile_dev_widget.mobileprovision")
|
# Certificate is imported by GHA workflow into build.keychain
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development", force: true)
|
||||||
|
main_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development.ShareExtension", force: true)
|
||||||
|
share_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
|
sigh(api_key: api_key, app_identifier: "#{BASE_BUNDLE_ID}.development.Widget", force: true)
|
||||||
|
widget_profile_name = lane_context[SharedValues::SIGH_NAME]
|
||||||
|
|
||||||
# Configure code signing for dev bundle IDs
|
# Configure code signing for dev bundle IDs
|
||||||
configure_code_signing(bundle_id_suffix: "development")
|
configure_code_signing(
|
||||||
|
bundle_id_suffix: "development",
|
||||||
|
profile_name_main: main_profile_name,
|
||||||
|
profile_name_share: share_profile_name,
|
||||||
|
profile_name_widget: widget_profile_name
|
||||||
|
)
|
||||||
|
|
||||||
# Build the app (same as gha_testflight_dev but without upload)
|
# Build the app (same as gha_testflight_dev but without upload)
|
||||||
build_app(
|
build_app(
|
||||||
|
|
@ -233,9 +277,9 @@ end
|
||||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
||||||
export_options: {
|
export_options: {
|
||||||
provisioningProfiles: {
|
provisioningProfiles: {
|
||||||
"#{BASE_BUNDLE_ID}.development" => "#{BASE_BUNDLE_ID}.development AppStore",
|
"#{BASE_BUNDLE_ID}.development" => main_profile_name,
|
||||||
"#{BASE_BUNDLE_ID}.development.ShareExtension" => "#{BASE_BUNDLE_ID}.development.ShareExtension AppStore",
|
"#{BASE_BUNDLE_ID}.development.ShareExtension" => share_profile_name,
|
||||||
"#{BASE_BUNDLE_ID}.development.Widget" => "#{BASE_BUNDLE_ID}.development.Widget AppStore"
|
"#{BASE_BUNDLE_ID}.development.Widget" => widget_profile_name
|
||||||
},
|
},
|
||||||
signingStyle: "manual",
|
signingStyle: "manual",
|
||||||
signingCertificate: CODE_SIGN_IDENTITY
|
signingCertificate: CODE_SIGN_IDENTITY
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue