Skip to content

Commit 4a3288c

Browse files
committed
Add automated Foundation Lab TestFlight workflow
1 parent a0e9e86 commit 4a3288c

5 files changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>method</key>
6+
<string>app-store-connect</string>
7+
<key>signingStyle</key>
8+
<string>automatic</string>
9+
<key>teamID</key>
10+
<string>YQZQG7N4WG</string>
11+
</dict>
12+
</plist>

.asc/workflow.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"env": {
3+
"PROJECT_PATH": "FoundationLab.xcodeproj",
4+
"SCHEME": "Foundation Lab",
5+
"CONFIGURATION": "Release",
6+
"EXPORT_OPTIONS": ".asc/ExportOptions/TestFlight.plist"
7+
},
8+
"before_all": "asc auth status --validate",
9+
"workflows": {
10+
"foundation_lab_testflight": {
11+
"description": "Archive, export, and upload Foundation Lab to the external TestFlight Beta group.",
12+
"steps": [
13+
{
14+
"name": "prepare_artifacts",
15+
"run": "mkdir -p .asc/artifacts .asc/runs"
16+
},
17+
{
18+
"name": "validate_inputs",
19+
"run": "for key in APP_ID TESTFLIGHT_GROUP TARGET_BUNDLE_ID TEAM_ID VERSION; do if [ -z \"${!key}\" ]; then echo \"$key is required\" >&2; exit 1; fi; done"
20+
},
21+
{
22+
"name": "resolve_next_build",
23+
"run": "asc builds next-build-number --app \"$APP_ID\" --version \"$VERSION\" --platform IOS --initial-build-number 1 --output json",
24+
"outputs": {
25+
"BUILD_NUMBER": "$.nextBuildNumber"
26+
}
27+
},
28+
{
29+
"name": "archive",
30+
"run": "asc xcode archive --project \"$PROJECT_PATH\" --scheme \"$SCHEME\" --configuration \"$CONFIGURATION\" --archive-path \".asc/artifacts/FoundationLab-$VERSION-${steps.resolve_next_build.BUILD_NUMBER}.xcarchive\" --clean --overwrite --xcodebuild-flag=-destination --xcodebuild-flag=generic/platform=iOS --xcodebuild-flag=-allowProvisioningUpdates --xcodebuild-flag=-authenticationKeyID --xcodebuild-flag=$ASC_KEY_ID --xcodebuild-flag=-authenticationKeyIssuerID --xcodebuild-flag=$ASC_ISSUER_ID --xcodebuild-flag=-authenticationKeyPath --xcodebuild-flag=$ASC_PRIVATE_KEY_PATH --xcodebuild-flag=PRODUCT_BUNDLE_IDENTIFIER=$TARGET_BUNDLE_ID --xcodebuild-flag=DEVELOPMENT_TEAM=$TEAM_ID --xcodebuild-flag=MARKETING_VERSION=$VERSION --xcodebuild-flag=CURRENT_PROJECT_VERSION=${steps.resolve_next_build.BUILD_NUMBER} --output json",
31+
"outputs": {
32+
"ARCHIVE_PATH": "$.archive_path",
33+
"VERSION": "$.version",
34+
"BUILD_NUMBER": "$.build_number"
35+
}
36+
},
37+
{
38+
"name": "export",
39+
"run": "asc xcode export --archive-path ${steps.archive.ARCHIVE_PATH} --export-options \"$EXPORT_OPTIONS\" --ipa-path \".asc/artifacts/FoundationLab-$VERSION-${steps.archive.BUILD_NUMBER}.ipa\" --overwrite --xcodebuild-flag=-allowProvisioningUpdates --xcodebuild-flag=-authenticationKeyID --xcodebuild-flag=$ASC_KEY_ID --xcodebuild-flag=-authenticationKeyIssuerID --xcodebuild-flag=$ASC_ISSUER_ID --xcodebuild-flag=-authenticationKeyPath --xcodebuild-flag=$ASC_PRIVATE_KEY_PATH --output json",
40+
"outputs": {
41+
"IPA_PATH": "$.ipa_path",
42+
"VERSION": "$.version",
43+
"BUILD_NUMBER": "$.build_number"
44+
}
45+
},
46+
{
47+
"name": "publish",
48+
"run": "asc publish testflight --app \"$APP_ID\" --ipa ${steps.export.IPA_PATH} --group \"$TESTFLIGHT_GROUP\" --wait --poll-interval 10s --output json",
49+
"outputs": {
50+
"BUILD_ID": "$.buildId",
51+
"BUILD_NUMBER": "$.buildNumber"
52+
}
53+
}
54+
]
55+
}
56+
}
57+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Foundation Lab TestFlight
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'Foundation Lab/**'
9+
- 'Foundation Lab.icon/**'
10+
- 'FoundationLabCore/**'
11+
- 'FoundationLab.xcodeproj/**'
12+
- 'SampleCode.xcconfig'
13+
- '.asc/**'
14+
- '.github/workflows/foundation-lab-testflight.yml'
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
group: foundation-lab-testflight
22+
cancel-in-progress: false
23+
24+
jobs:
25+
upload:
26+
runs-on: macos-latest
27+
timeout-minutes: 90
28+
env:
29+
ASC_BYPASS_KEYCHAIN: "1"
30+
APP_ID: ${{ vars.FOUNDATION_LAB_APP_ID }}
31+
TESTFLIGHT_GROUP: ${{ vars.FOUNDATION_LAB_EXTERNAL_GROUP_ID }}
32+
TARGET_BUNDLE_ID: ${{ vars.FOUNDATION_LAB_BUNDLE_ID }}
33+
TEAM_ID: ${{ vars.FOUNDATION_LAB_TEAM_ID }}
34+
steps:
35+
- name: Check out repository
36+
uses: actions/checkout@v4
37+
38+
- name: Select Xcode
39+
uses: maxim-lobanov/setup-xcode@v1
40+
with:
41+
xcode-version: latest-stable
42+
43+
- name: Install asc
44+
run: |
45+
HOMEBREW_NO_AUTO_UPDATE=1 brew install asc
46+
asc --version
47+
48+
- name: Validate repository configuration
49+
env:
50+
ASC_KEY_ID_SECRET: ${{ secrets.ASC_KEY_ID }}
51+
ASC_ISSUER_ID_SECRET: ${{ secrets.ASC_ISSUER_ID }}
52+
ASC_PRIVATE_KEY_B64_SECRET: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
53+
run: |
54+
for key in APP_ID TESTFLIGHT_GROUP TARGET_BUNDLE_ID TEAM_ID; do
55+
if [ -z "${!key}" ]; then
56+
echo "Missing required repository variable: $key" >&2
57+
exit 1
58+
fi
59+
done
60+
61+
for key in ASC_KEY_ID_SECRET ASC_ISSUER_ID_SECRET ASC_PRIVATE_KEY_B64_SECRET; do
62+
if [ -z "${!key}" ]; then
63+
echo "Missing required repository secret: ${key%_SECRET}" >&2
64+
exit 1
65+
fi
66+
done
67+
68+
- name: Materialize ASC key
69+
env:
70+
ASC_KEY_ID_SECRET: ${{ secrets.ASC_KEY_ID }}
71+
ASC_ISSUER_ID_SECRET: ${{ secrets.ASC_ISSUER_ID }}
72+
ASC_PRIVATE_KEY_B64_SECRET: ${{ secrets.ASC_PRIVATE_KEY_B64 }}
73+
run: |
74+
KEY_PATH="$RUNNER_TEMP/AuthKey_${ASC_KEY_ID_SECRET}.p8"
75+
printf '%s' "$ASC_PRIVATE_KEY_B64_SECRET" | base64 --decode > "$KEY_PATH"
76+
chmod 600 "$KEY_PATH"
77+
78+
{
79+
echo "ASC_KEY_ID=$ASC_KEY_ID_SECRET"
80+
echo "ASC_ISSUER_ID=$ASC_ISSUER_ID_SECRET"
81+
echo "ASC_PRIVATE_KEY_PATH=$KEY_PATH"
82+
} >> "$GITHUB_ENV"
83+
84+
- name: Resolve marketing version
85+
id: version
86+
run: |
87+
VERSION="$(xcodebuild -showBuildSettings \
88+
-project FoundationLab.xcodeproj \
89+
-scheme 'Foundation Lab' \
90+
-configuration Release \
91+
-destination 'generic/platform=iOS' | awk '/MARKETING_VERSION = / { print $3; exit }')"
92+
93+
if [ -z "$VERSION" ]; then
94+
echo "Failed to resolve MARKETING_VERSION" >&2
95+
exit 1
96+
fi
97+
98+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
99+
100+
- name: Validate ASC workflow
101+
run: asc workflow validate
102+
103+
- name: Dry run ASC workflow
104+
run: asc workflow run --dry-run foundation_lab_testflight VERSION:${{ steps.version.outputs.version }}
105+
106+
- name: Upload to TestFlight external group
107+
run: asc workflow run foundation_lab_testflight VERSION:${{ steps.version.outputs.version }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ xcuserdata/
1313
*.dSYM.zip
1414
*.dSYM
1515

16+
.asc/artifacts/
17+
.asc/runs/
18+
1619
## Playgrounds
1720
timeline.xctimeline
1821
playground.xcworkspace

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@ It is part of the [Exploring Foundation Models](https://academy.rudrank.com/prod
4747

4848
You can now try Foundation Lab on TestFlight! Join the beta: [https://testflight.apple.com/join/JWR9FpP3](https://testflight.apple.com/join/JWR9FpP3)
4949

50+
## Automated TestFlight uploads
51+
52+
This repo includes a repo-local ASC workflow in `.asc/workflow.json` and a GitHub Actions workflow in `.github/workflows/foundation-lab-testflight.yml` that uploads the iOS app to the external TestFlight Beta group whenever app changes land on `main`.
53+
54+
GitHub Actions expects these repository secrets:
55+
56+
- `ASC_KEY_ID`
57+
- `ASC_ISSUER_ID`
58+
- `ASC_PRIVATE_KEY_B64`
59+
60+
It also expects these repository variables:
61+
62+
- `FOUNDATION_LAB_APP_ID`
63+
- `FOUNDATION_LAB_EXTERNAL_GROUP_ID`
64+
- `FOUNDATION_LAB_BUNDLE_ID`
65+
- `FOUNDATION_LAB_TEAM_ID`
66+
5067
## Getting Started
5168

5269
- Clone the repository

0 commit comments

Comments
 (0)