Fastlane TestFlight (#1179)

* init

* get last values from secrets
This commit is contained in:
Ethan Pippin 2024-08-13 13:37:46 -06:00 committed by GitHub
parent 7f023b3830
commit 32f23ff295
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 170 additions and 18 deletions

70
.github/workflows/testflight.yml vendored Normal file
View File

@ -0,0 +1,70 @@
name: "TestFlight ⚙️"
on:
repository_dispatch:
types: [testflight]
jobs:
test_build:
runs-on: macos-14
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: git Checkout
if: ${{ github.event.client_payload.hasCheckoutCommit }}
run: |
git checkout ${{ github.event.client_payload.commitSHA }}
- run: 'echo "$SSH_KEY" > key'
shell: bash
env:
SSH_KEY: ${{secrets.P12_PASSWORD}}
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: "CI_PASSWORD"
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
sudo mkdir -p /Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
sudo cp $PP_PATH /Library/MobileDevice/Provisioning\ Profiles
- name: Build and Upload to TestFlight
run: sudo fastlane testFlightLane \
keyID:${{ secrets.APP_STORE_KEY_ID }} \
issuerID:${{ secrets.APP_STORE_ISSUER_ID }} \
keyContents:${{ secrets.APP_STORE_KEY_CONTENTS }} \
scheme:${{ github.event.client_payload.scheme }} \
codeSign64:${{ secrets.CODE_SIGN_64 }} \
profileName64:${{ secrets.PROFILE_NAME_64 }} \
xcodeVersion:${{ github.event.client_payload.xcodeVersion }} \
build:${{ github.event.client_payload.build }} \
version:${{ github.event.client_payload.version }}

View File

@ -63,6 +63,82 @@ class Fastfile: LaneFile {
)
}
// MARK: TestFlight
// TODO: verify tvOS
func testFlightLane(withOptions options: [String: String]?) {
guard let options,
let keyID = options["keyID"],
let issuerID = options["issuerID"],
let keyContents = options["keyContents"],
let scheme = options["scheme"],
let codeSign64 = options["codeSign64"],
let profileName64 = options["profileName64"]
else {
puts(message: "ERROR: missing or incorrect options")
exit(1)
}
guard let decodedCodeSignIdentity = decodeBase64(encoded: codeSign64) else {
puts(message: "ERROR: code sign identity not valid base 64")
exit(1)
}
guard let profileName = decodeBase64(encoded: profileName64) else {
puts(message: "ERROR: profile name not valid base 64")
exit(1)
}
if let xcodeVersion = options["xcodeVersion"] {
xcodes(version: xcodeVersion)
}
appStoreConnectApiKey(
keyId: keyID,
issuerId: .userDefined(issuerID),
keyContent: .userDefined(keyContents),
isKeyContentBase64: true,
duration: 1200,
inHouse: false
)
updateCodeSigningSettings(
path: "Swiftfin.xcodeproj",
useAutomaticSigning: false,
codeSignIdentity: .userDefined(decodedCodeSignIdentity),
profileName: .userDefined(profileName)
)
if let version = options["version"] {
incrementVersionNumber(
versionNumber: .userDefined(version),
xcodeproj: "Swiftfin.xcodeproj"
)
}
if let build = options["build"] {
incrementBuildNumber(
buildNumber: .userDefined(build),
xcodeproj: "Swiftfin.xcodeproj"
)
} else {
incrementBuildNumber(
xcodeproj: "Swiftfin.xcodeproj"
)
}
buildApp(
scheme: .userDefined(scheme),
skipArchive: .userDefined(false),
skipProfileDetection: false
)
uploadToTestflight(
ipa: "Swiftfin.ipa"
)
}
// MARK: Utilities
private func decodeBase64(encoded: String) -> String? {

View File

@ -95,7 +95,7 @@ public protocol DeliverfileProtocol: AnyObject {
/// Path to the app rating's config
var appRatingConfigPath: String? { get }
/// Extra information for the submission (e.g. compliance specifications, IDFA settings)
/// Extra information for the submission (e.g. compliance specifications)
var submissionInformation: [String: Any]? { get }
/// The ID of your App Store Connect team if you're in multiple teams
@ -272,4 +272,4 @@ public extension DeliverfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.124]
// FastlaneRunnerAPIVersion [0.9.127]

View File

@ -190,7 +190,7 @@ public func appStoreBuildNumber(apiKeyPath: OptionalConfigValue<String?> = .fast
- parameters:
- keyId: The key ID
- issuerId: The issuer ID
- issuerId: The issuer ID. It can be nil if the key is individual API key
- keyFilepath: The path to the key p8 file
- keyContent: The content of the key p8 file
- isKeyContentBase64: Whether :key_content is Base64 encoded or not
@ -201,7 +201,7 @@ public func appStoreBuildNumber(apiKeyPath: OptionalConfigValue<String?> = .fast
Load the App Store Connect API token to use in other fastlane tools and actions
*/
public func appStoreConnectApiKey(keyId: String,
issuerId: String,
issuerId: OptionalConfigValue<String?> = .fastlaneDefault(nil),
keyFilepath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
keyContent: OptionalConfigValue<String?> = .fastlaneDefault(nil),
isKeyContentBase64: OptionalConfigValue<Bool> = .fastlaneDefault(false),
@ -210,7 +210,7 @@ public func appStoreConnectApiKey(keyId: String,
setSpaceshipToken: OptionalConfigValue<Bool> = .fastlaneDefault(true))
{
let keyIdArg = RubyCommand.Argument(name: "key_id", value: keyId, type: nil)
let issuerIdArg = RubyCommand.Argument(name: "issuer_id", value: issuerId, type: nil)
let issuerIdArg = issuerId.asRubyArgument(name: "issuer_id", type: nil)
let keyFilepathArg = keyFilepath.asRubyArgument(name: "key_filepath", type: nil)
let keyContentArg = keyContent.asRubyArgument(name: "key_content", type: nil)
let isKeyContentBase64Arg = isKeyContentBase64.asRubyArgument(name: "is_key_content_base64", type: nil)
@ -674,7 +674,7 @@ public func appledoc(input: [String],
- resetRatings: Reset the summary rating when you release a new version of the application
- priceTier: The price tier of this application
- appRatingConfigPath: Path to the app rating's config
- submissionInformation: Extra information for the submission (e.g. compliance specifications, IDFA settings)
- submissionInformation: Extra information for the submission (e.g. compliance specifications)
- teamId: The ID of your App Store Connect team if you're in multiple teams
- teamName: The name of your App Store Connect team if you're in multiple teams
- devPortalTeamId: The short ID of your Developer Portal team, if you're in multiple teams. Different from your iTC team ID!
@ -3714,7 +3714,7 @@ public func deleteKeychain(name: OptionalConfigValue<String?> = .fastlaneDefault
- resetRatings: Reset the summary rating when you release a new version of the application
- priceTier: The price tier of this application
- appRatingConfigPath: Path to the app rating's config
- submissionInformation: Extra information for the submission (e.g. compliance specifications, IDFA settings)
- submissionInformation: Extra information for the submission (e.g. compliance specifications)
- teamId: The ID of your App Store Connect team if you're in multiple teams
- teamName: The name of your App Store Connect team if you're in multiple teams
- devPortalTeamId: The short ID of your Developer Portal team, if you're in multiple teams. Different from your iTC team ID!
@ -4096,7 +4096,7 @@ public func downloadAppPrivacyDetailsFromAppStore(username: String,
- appIdentifier: The bundle identifier of your app
- teamId: The ID of your App Store Connect team if you're in multiple teams
- teamName: The name of your App Store Connect team if you're in multiple teams
- platform: The app platform for dSYMs you wish to download (ios, appletvos)
- platform: The app platform for dSYMs you wish to download (ios, xros, appletvos)
- version: The app version for dSYMs you wish to download, pass in 'latest' to download only the latest build's dSYMs or 'live' to download only the live version dSYMs
- buildNumber: The app build_number for dSYMs you wish to download
- minVersion: The minimum app version for dSYMs you wish to download
@ -9707,7 +9707,7 @@ public func setBuildNumberRepository(useHgRevisionNumber: OptionalConfigValue<Bo
- changelog: Changelog text that should be uploaded to App Store Connect
- teamId: The ID of your App Store Connect team if you're in multiple teams
- teamName: The name of your App Store Connect team if you're in multiple teams
- platform: The platform of the app (ios, appletvos, mac)
- platform: The platform of the app (ios, appletvos, xros, mac)
This is useful if you have only one changelog for all languages.
You can store the changelog in `./changelog.txt` and it will automatically get loaded from there. This integration is useful if you support e.g. 10 languages and want to use the same "What's new"-text for all languages.
@ -10938,6 +10938,7 @@ public func splunkmint(dsym: OptionalConfigValue<String?> = .fastlaneDefault(nil
- xcprettyOutput: Specifies the output type for xcpretty. eg. 'test', or 'simple'
- xcprettyArgs: Pass in xcpretty additional command line arguments (e.g. '--test --no-color' or '--tap --no-utf'), requires xcpretty_output to be specified also
- verbose: Increase verbosity of informational output
- veryVerbose: Increase verbosity to include debug output
- simulator: Specifies the simulator to pass for Swift Compiler (one of: iphonesimulator, macosx)
- simulatorArch: Specifies the architecture of the simulator to pass for Swift Compiler (one of: x86_64, arm64). Requires the simulator option to be specified also, otherwise, it's ignored
*/
@ -10953,6 +10954,7 @@ public func spm(command: String = "build",
xcprettyOutput: OptionalConfigValue<String?> = .fastlaneDefault(nil),
xcprettyArgs: OptionalConfigValue<String?> = .fastlaneDefault(nil),
verbose: OptionalConfigValue<Bool> = .fastlaneDefault(false),
veryVerbose: OptionalConfigValue<Bool> = .fastlaneDefault(false),
simulator: OptionalConfigValue<String?> = .fastlaneDefault(nil),
simulatorArch: String = "arm64")
{
@ -10968,6 +10970,7 @@ public func spm(command: String = "build",
let xcprettyOutputArg = xcprettyOutput.asRubyArgument(name: "xcpretty_output", type: nil)
let xcprettyArgsArg = xcprettyArgs.asRubyArgument(name: "xcpretty_args", type: nil)
let verboseArg = verbose.asRubyArgument(name: "verbose", type: nil)
let veryVerboseArg = veryVerbose.asRubyArgument(name: "very_verbose", type: nil)
let simulatorArg = simulator.asRubyArgument(name: "simulator", type: nil)
let simulatorArchArg = RubyCommand.Argument(name: "simulator_arch", value: simulatorArch, type: nil)
let array: [RubyCommand.Argument?] = [commandArg,
@ -10982,6 +10985,7 @@ public func spm(command: String = "build",
xcprettyOutputArg,
xcprettyArgsArg,
verboseArg,
veryVerboseArg,
simulatorArg,
simulatorArchArg]
let args: [RubyCommand.Argument] = array
@ -12536,7 +12540,7 @@ public func uploadSymbolsToSentry(apiHost: String = "https://app.getsentry.com/a
- resetRatings: Reset the summary rating when you release a new version of the application
- priceTier: The price tier of this application
- appRatingConfigPath: Path to the app rating's config
- submissionInformation: Extra information for the submission (e.g. compliance specifications, IDFA settings)
- submissionInformation: Extra information for the submission (e.g. compliance specifications)
- teamId: The ID of your App Store Connect team if you're in multiple teams
- teamName: The name of your App Store Connect team if you're in multiple teams
- devPortalTeamId: The short ID of your Developer Portal team, if you're in multiple teams. Different from your iTC team ID!
@ -13594,7 +13598,7 @@ public func xcov(workspace: OptionalConfigValue<String?> = .fastlaneDefault(nil)
coverallsServiceJobId: OptionalConfigValue<String?> = .fastlaneDefault(nil),
coverallsRepoToken: OptionalConfigValue<String?> = .fastlaneDefault(nil),
xcconfig: OptionalConfigValue<String?> = .fastlaneDefault(nil),
ideFoundationPath: String = "/Applications/Xcode-15.3.0.app/Contents/Developer/../Frameworks/IDEFoundation.framework/Versions/A/IDEFoundation",
ideFoundationPath: String = "/Applications/Xcode_15.4.app/Contents/Developer/../Frameworks/IDEFoundation.framework/Versions/A/IDEFoundation",
legacySupport: OptionalConfigValue<Bool> = .fastlaneDefault(false))
{
let workspaceArg = workspace.asRubyArgument(name: "workspace", type: nil)
@ -13797,4 +13801,4 @@ public let snapshotfile: Snapshotfile = .init()
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.177]
// FastlaneRunnerAPIVersion [0.9.180]

View File

@ -404,6 +404,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
@ -416,6 +417,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
};

View File

@ -208,4 +208,4 @@ public extension GymfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.127]
// FastlaneRunnerAPIVersion [0.9.130]

View File

@ -228,4 +228,4 @@ public extension MatchfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.121]
// FastlaneRunnerAPIVersion [0.9.124]

View File

@ -52,4 +52,4 @@ public extension PrecheckfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.120]
// FastlaneRunnerAPIVersion [0.9.123]

View File

@ -320,4 +320,4 @@ public extension ScanfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.132]
// FastlaneRunnerAPIVersion [0.9.135]

View File

@ -96,4 +96,4 @@ public extension ScreengrabfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.122]
// FastlaneRunnerAPIVersion [0.9.125]

View File

@ -204,4 +204,4 @@ public extension SnapshotfileProtocol {
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.116]
// FastlaneRunnerAPIVersion [0.9.119]