Skip to content

Commit 0b01cf9

Browse files
ps2budsterblue
andauthoredDec 14, 2022
FastLane + GitHub Actions + TestFlight = Mac-free Loop install (LoopKit#26)
FastLane + GitHub Actions + TestFlight supporting changes. Co-authored-by: budsterblue <budsterblue@gmail.com>
1 parent 5e13d94 commit 0b01cf9

File tree

8 files changed

+687
-0
lines changed

8 files changed

+687
-0
lines changed
 

‎.github/workflows/add_identifiers.yml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Add Identifiers
2+
on:
3+
workflow_dispatch:
4+
5+
jobs:
6+
identifiers:
7+
runs-on: macos-12
8+
steps:
9+
# Uncomment to manually select latest Xcode if needed
10+
#- name: Select Latest Xcode
11+
# run: "sudo xcode-select --switch /Applications/Xcode_13.0.app/Contents/Developer"
12+
13+
# Checks-out the repo
14+
- name: Checkout Repo
15+
uses: actions/checkout@v2
16+
17+
# Patch Fastlane Match to not print tables
18+
- name: Patch Match Tables
19+
run: find /usr/local/lib/ruby/gems -name table_printer.rb | xargs sed -i "" "/puts(Terminal::Table.new(params))/d"
20+
21+
# Create or update identifiers for app
22+
- name: Fastlane Provision
23+
run: fastlane identifiers
24+
env:
25+
TEAMID: ${{ secrets.TEAMID }}
26+
GH_PAT: ${{ secrets.GH_PAT }}
27+
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
28+
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
29+
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
30+
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}

‎.github/workflows/build_loop.yml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Build Loop
2+
on:
3+
workflow_dispatch:
4+
5+
jobs:
6+
build:
7+
runs-on: macos-12
8+
steps:
9+
# Uncomment to manually select latest Xcode if needed
10+
- name: Select Latest Xcode
11+
run: "sudo xcode-select --switch /Applications/Xcode_14.1.app/Contents/Developer"
12+
13+
# Checks-out the repo
14+
- name: Checkout Repo
15+
uses: actions/checkout@v2
16+
with:
17+
submodules: recursive
18+
19+
# Patch Fastlane Match to not print tables
20+
- name: Patch Match Tables
21+
run: find /usr/local/lib/ruby/gems -name table_printer.rb | xargs sed -i "" "/puts(Terminal::Table.new(params))/d"
22+
23+
# Build signed Loop IPA file
24+
- name: Fastlane Build & Archive
25+
run: fastlane build_loop
26+
env:
27+
TEAMID: ${{ secrets.TEAMID }}
28+
GH_PAT: ${{ secrets.GH_PAT }}
29+
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
30+
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
31+
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
32+
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
33+
34+
# Upload encrypted output as artifact
35+
- name: Fastlane upload to TestFlight
36+
run: fastlane release
37+
env:
38+
TEAMID: ${{ secrets.TEAMID }}
39+
GH_PAT: ${{ secrets.GH_PAT }}
40+
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
41+
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
42+
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
43+
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}

‎.github/workflows/create_certs.yml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Create Certificates
2+
on:
3+
workflow_dispatch:
4+
5+
jobs:
6+
certificates:
7+
runs-on: macos-12
8+
steps:
9+
# Uncomment to manually select latest Xcode if needed
10+
#- name: Select Latest Xcode
11+
# run: "sudo xcode-select --switch /Applications/Xcode_13.0.app/Contents/Developer"
12+
13+
# Checks-out the repo
14+
- name: Checkout Repo
15+
uses: actions/checkout@v2
16+
17+
# Patch Fastlane Match to not print tables
18+
- name: Patch Match Tables
19+
run: find /usr/local/lib/ruby/gems -name table_printer.rb | xargs sed -i "" "/puts(Terminal::Table.new(params))/d"
20+
21+
# Create or update certificates for app
22+
- name: Create Certificates
23+
run: fastlane certs
24+
env:
25+
TEAMID: ${{ secrets.TEAMID }}
26+
GH_PAT: ${{ secrets.GH_PAT }}
27+
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
28+
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
29+
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
30+
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}

‎Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source "https://rubygems.org"
2+
3+
gem "fastlane"

‎Gemfile.lock

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
CFPropertyList (3.0.4)
5+
rexml
6+
addressable (2.8.0)
7+
public_suffix (>= 2.0.2, < 5.0)
8+
artifactory (3.0.15)
9+
atomos (0.1.3)
10+
aws-eventstream (1.2.0)
11+
aws-partitions (1.516.0)
12+
aws-sdk-core (3.121.2)
13+
aws-eventstream (~> 1, >= 1.0.2)
14+
aws-partitions (~> 1, >= 1.239.0)
15+
aws-sigv4 (~> 1.1)
16+
jmespath (~> 1.0)
17+
aws-sdk-kms (1.50.0)
18+
aws-sdk-core (~> 3, >= 3.121.2)
19+
aws-sigv4 (~> 1.1)
20+
aws-sdk-s3 (1.104.0)
21+
aws-sdk-core (~> 3, >= 3.121.2)
22+
aws-sdk-kms (~> 1)
23+
aws-sigv4 (~> 1.4)
24+
aws-sigv4 (1.4.0)
25+
aws-eventstream (~> 1, >= 1.0.2)
26+
babosa (1.0.4)
27+
claide (1.0.3)
28+
colored (1.2)
29+
colored2 (3.1.2)
30+
commander (4.6.0)
31+
highline (~> 2.0.0)
32+
declarative (0.0.20)
33+
digest-crc (0.6.4)
34+
rake (>= 12.0.0, < 14.0.0)
35+
domain_name (0.5.20190701)
36+
unf (>= 0.0.5, < 1.0.0)
37+
dotenv (2.7.6)
38+
emoji_regex (3.2.3)
39+
excon (0.87.0)
40+
faraday (1.8.0)
41+
faraday-em_http (~> 1.0)
42+
faraday-em_synchrony (~> 1.0)
43+
faraday-excon (~> 1.1)
44+
faraday-httpclient (~> 1.0.1)
45+
faraday-net_http (~> 1.0)
46+
faraday-net_http_persistent (~> 1.1)
47+
faraday-patron (~> 1.0)
48+
faraday-rack (~> 1.0)
49+
multipart-post (>= 1.2, < 3)
50+
ruby2_keywords (>= 0.0.4)
51+
faraday-cookie_jar (0.0.7)
52+
faraday (>= 0.8.0)
53+
http-cookie (~> 1.0.0)
54+
faraday-em_http (1.0.0)
55+
faraday-em_synchrony (1.0.0)
56+
faraday-excon (1.1.0)
57+
faraday-httpclient (1.0.1)
58+
faraday-net_http (1.0.1)
59+
faraday-net_http_persistent (1.2.0)
60+
faraday-patron (1.0.0)
61+
faraday-rack (1.0.0)
62+
faraday_middleware (1.2.0)
63+
faraday (~> 1.0)
64+
fastimage (2.2.5)
65+
fastlane (2.196.0)
66+
CFPropertyList (>= 2.3, < 4.0.0)
67+
addressable (>= 2.8, < 3.0.0)
68+
artifactory (~> 3.0)
69+
aws-sdk-s3 (~> 1.0)
70+
babosa (>= 1.0.3, < 2.0.0)
71+
bundler (>= 1.12.0, < 3.0.0)
72+
colored
73+
commander (~> 4.6)
74+
dotenv (>= 2.1.1, < 3.0.0)
75+
emoji_regex (>= 0.1, < 4.0)
76+
excon (>= 0.71.0, < 1.0.0)
77+
faraday (~> 1.0)
78+
faraday-cookie_jar (~> 0.0.6)
79+
faraday_middleware (~> 1.0)
80+
fastimage (>= 2.1.0, < 3.0.0)
81+
gh_inspector (>= 1.1.2, < 2.0.0)
82+
google-apis-androidpublisher_v3 (~> 0.3)
83+
google-apis-playcustomapp_v1 (~> 0.1)
84+
google-cloud-storage (~> 1.31)
85+
highline (~> 2.0)
86+
json (< 3.0.0)
87+
jwt (>= 2.1.0, < 3)
88+
mini_magick (>= 4.9.4, < 5.0.0)
89+
multipart-post (~> 2.0.0)
90+
naturally (~> 2.2)
91+
optparse (~> 0.1.1)
92+
plist (>= 3.1.0, < 4.0.0)
93+
rubyzip (>= 2.0.0, < 3.0.0)
94+
security (= 0.1.3)
95+
simctl (~> 1.6.3)
96+
terminal-notifier (>= 2.0.0, < 3.0.0)
97+
terminal-table (>= 1.4.5, < 2.0.0)
98+
tty-screen (>= 0.6.3, < 1.0.0)
99+
tty-spinner (>= 0.8.0, < 1.0.0)
100+
word_wrap (~> 1.0.0)
101+
xcodeproj (>= 1.13.0, < 2.0.0)
102+
xcpretty (~> 0.3.0)
103+
xcpretty-travis-formatter (>= 0.0.3)
104+
gh_inspector (1.1.3)
105+
google-apis-androidpublisher_v3 (0.12.0)
106+
google-apis-core (>= 0.4, < 2.a)
107+
google-apis-core (0.4.1)
108+
addressable (~> 2.5, >= 2.5.1)
109+
googleauth (>= 0.16.2, < 2.a)
110+
httpclient (>= 2.8.1, < 3.a)
111+
mini_mime (~> 1.0)
112+
representable (~> 3.0)
113+
retriable (>= 2.0, < 4.a)
114+
rexml
115+
webrick
116+
google-apis-iamcredentials_v1 (0.7.0)
117+
google-apis-core (>= 0.4, < 2.a)
118+
google-apis-playcustomapp_v1 (0.5.0)
119+
google-apis-core (>= 0.4, < 2.a)
120+
google-apis-storage_v1 (0.8.0)
121+
google-apis-core (>= 0.4, < 2.a)
122+
google-cloud-core (1.6.0)
123+
google-cloud-env (~> 1.0)
124+
google-cloud-errors (~> 1.0)
125+
google-cloud-env (1.5.0)
126+
faraday (>= 0.17.3, < 2.0)
127+
google-cloud-errors (1.2.0)
128+
google-cloud-storage (1.34.1)
129+
addressable (~> 2.5)
130+
digest-crc (~> 0.4)
131+
google-apis-iamcredentials_v1 (~> 0.1)
132+
google-apis-storage_v1 (~> 0.1)
133+
google-cloud-core (~> 1.6)
134+
googleauth (>= 0.16.2, < 2.a)
135+
mini_mime (~> 1.0)
136+
googleauth (1.0.0)
137+
faraday (>= 0.17.3, < 2.0)
138+
jwt (>= 1.4, < 3.0)
139+
memoist (~> 0.16)
140+
multi_json (~> 1.11)
141+
os (>= 0.9, < 2.0)
142+
signet (>= 0.16, < 2.a)
143+
highline (2.0.3)
144+
http-cookie (1.0.4)
145+
domain_name (~> 0.5)
146+
httpclient (2.8.3)
147+
jmespath (1.4.0)
148+
json (2.6.0)
149+
jwt (2.3.0)
150+
memoist (0.16.2)
151+
mini_magick (4.11.0)
152+
mini_mime (1.1.2)
153+
multi_json (1.15.0)
154+
multipart-post (2.0.0)
155+
nanaimo (0.3.0)
156+
naturally (2.2.1)
157+
optparse (0.1.1)
158+
os (1.1.1)
159+
plist (3.6.0)
160+
public_suffix (4.0.6)
161+
rake (13.0.6)
162+
representable (3.1.1)
163+
declarative (< 0.1.0)
164+
trailblazer-option (>= 0.1.1, < 0.2.0)
165+
uber (< 0.2.0)
166+
retriable (3.1.2)
167+
rexml (3.2.5)
168+
rouge (2.0.7)
169+
ruby2_keywords (0.0.5)
170+
rubyzip (2.3.2)
171+
security (0.1.3)
172+
signet (0.16.0)
173+
addressable (~> 2.8)
174+
faraday (>= 0.17.3, < 2.0)
175+
jwt (>= 1.5, < 3.0)
176+
multi_json (~> 1.10)
177+
simctl (1.6.8)
178+
CFPropertyList
179+
naturally
180+
terminal-notifier (2.0.0)
181+
terminal-table (1.8.0)
182+
unicode-display_width (~> 1.1, >= 1.1.1)
183+
trailblazer-option (0.1.1)
184+
tty-cursor (0.7.1)
185+
tty-screen (0.8.1)
186+
tty-spinner (0.9.3)
187+
tty-cursor (~> 0.7)
188+
uber (0.1.0)
189+
unf (0.1.4)
190+
unf_ext
191+
unf_ext (0.0.8)
192+
unicode-display_width (1.8.0)
193+
webrick (1.7.0)
194+
word_wrap (1.0.0)
195+
xcodeproj (1.21.0)
196+
CFPropertyList (>= 2.3.3, < 4.0)
197+
atomos (~> 0.1.3)
198+
claide (>= 1.0.2, < 2.0)
199+
colored2 (~> 3.1)
200+
nanaimo (~> 0.3.0)
201+
rexml (~> 3.2.4)
202+
xcpretty (0.3.0)
203+
rouge (~> 2.0.7)
204+
xcpretty-travis-formatter (1.0.1)
205+
xcpretty (~> 0.2, >= 0.0.7)
206+
207+
PLATFORMS
208+
arm64-darwin-21
209+
x86_64-darwin-19
210+
211+
DEPENDENCIES
212+
fastlane
213+
214+
BUNDLED WITH
215+
2.3.26

‎fastlane/Fastfile

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
# This file contains the fastlane.tools configuration
2+
# You can find the documentation at https://docs.fastlane.tools
3+
#
4+
# For a list of all available actions, check out
5+
#
6+
# https://docs.fastlane.tools/actions
7+
#
8+
# For a list of all available plugins, check out
9+
#
10+
# https://docs.fastlane.tools/plugins/available-plugins
11+
#
12+
13+
default_platform(:ios)
14+
15+
TEAMID = ENV["TEAMID"]
16+
GH_PAT = ENV["GH_PAT"]
17+
GITHUB_WORKSPACE = ENV["GITHUB_WORKSPACE"]
18+
GITHUB_REPOSITORY_OWNER = ENV["GITHUB_REPOSITORY_OWNER"]
19+
FASTLANE_KEY_ID = ENV["FASTLANE_KEY_ID"]
20+
FASTLANE_ISSUER_ID = ENV["FASTLANE_ISSUER_ID"]
21+
FASTLANE_KEY = ENV["FASTLANE_KEY"]
22+
DEVICE_NAME = ENV["DEVICE_NAME"]
23+
DEVICE_ID = ENV["DEVICE_ID"]
24+
ENV["FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT"] = "120"
25+
26+
platform :ios do
27+
desc "Build Loop"
28+
lane :build_loop do
29+
setup_ci if ENV['CI']
30+
31+
update_project_team(
32+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
33+
teamid: "#{TEAMID}"
34+
)
35+
36+
api_key = app_store_connect_api_key(
37+
key_id: "#{FASTLANE_KEY_ID}",
38+
issuer_id: "#{FASTLANE_ISSUER_ID}",
39+
key_content: "#{FASTLANE_KEY}"
40+
)
41+
42+
previous_build_number = latest_testflight_build_number(
43+
app_identifier: "com.#{TEAMID}.loopkit.Loop",
44+
api_key: api_key,
45+
)
46+
47+
current_build_number = previous_build_number + 1
48+
49+
increment_build_number(
50+
xcodeproj: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
51+
build_number: current_build_number
52+
)
53+
54+
match(
55+
type: "appstore",
56+
git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}"),
57+
app_identifier: [
58+
"com.#{TEAMID}.loopkit.Loop",
59+
"com.#{TEAMID}.loopkit.Loop.statuswidget",
60+
"com.#{TEAMID}.loopkit.Loop.LoopWatch.watchkitextension",
61+
"com.#{TEAMID}.loopkit.Loop.LoopWatch",
62+
"com.#{TEAMID}.loopkit.Loop.Loop-Intent-Extension",
63+
"com.#{TEAMID}.loopkit.Loop.SmallStatusWidget"
64+
]
65+
)
66+
67+
previous_build_number = latest_testflight_build_number(
68+
app_identifier: "com.#{TEAMID}.loopkit.Loop",
69+
api_key: api_key,
70+
)
71+
72+
current_build_number = previous_build_number + 1
73+
74+
increment_build_number(
75+
xcodeproj: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
76+
build_number: current_build_number
77+
)
78+
79+
mapping = Actions.lane_context[
80+
SharedValues::MATCH_PROVISIONING_PROFILE_MAPPING
81+
]
82+
83+
update_code_signing_settings(
84+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
85+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop"],
86+
code_sign_identity: "iPhone Distribution",
87+
targets: ["Loop"]
88+
)
89+
90+
update_code_signing_settings(
91+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
92+
code_sign_identity: "iPhone Distribution",
93+
targets: ["LoopCore", "LoopCore-watchOS", "LoopUI"]
94+
)
95+
96+
update_code_signing_settings(
97+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
98+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop.statuswidget"],
99+
code_sign_identity: "iPhone Distribution",
100+
targets: ["Loop Status Extension"]
101+
)
102+
103+
update_code_signing_settings(
104+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
105+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop.LoopWatch.watchkitextension"],
106+
code_sign_identity: "iPhone Distribution",
107+
targets: ["WatchApp Extension"]
108+
)
109+
110+
update_code_signing_settings(
111+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
112+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop.LoopWatch"],
113+
code_sign_identity: "iPhone Distribution",
114+
targets: ["WatchApp"]
115+
)
116+
117+
update_code_signing_settings(
118+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
119+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop.Loop-Intent-Extension"],
120+
code_sign_identity: "iPhone Distribution",
121+
targets: ["Loop Intent Extension"]
122+
)
123+
124+
update_code_signing_settings(
125+
path: "#{GITHUB_WORKSPACE}/Loop/Loop.xcodeproj",
126+
profile_name: mapping["com.#{TEAMID}.loopkit.Loop.SmallStatusWidget"],
127+
code_sign_identity: "iPhone Distribution",
128+
targets: ["SmallStatusWidgetExtension"]
129+
)
130+
131+
gym(
132+
export_method: "app-store",
133+
scheme: "Loop (Workspace)",
134+
output_name: "Loop.ipa",
135+
configuration: "Release",
136+
destination: 'generic/platform=iOS'
137+
)
138+
end
139+
140+
desc "Push to TestFlight"
141+
lane :release do
142+
api_key = app_store_connect_api_key(
143+
key_id: "#{FASTLANE_KEY_ID}",
144+
issuer_id: "#{FASTLANE_ISSUER_ID}",
145+
key_content: "#{FASTLANE_KEY}"
146+
)
147+
148+
upload_to_testflight(
149+
api_key: api_key,
150+
skip_submission: false,
151+
ipa: "Loop.ipa",
152+
skip_waiting_for_build_processing: true,
153+
)
154+
end
155+
156+
desc "Provision Identifiers and Certificates"
157+
lane :identifiers do
158+
setup_ci if ENV['CI']
159+
ENV["MATCH_READONLY"] = false.to_s
160+
161+
app_store_connect_api_key(
162+
key_id: "#{FASTLANE_KEY_ID}",
163+
issuer_id: "#{FASTLANE_ISSUER_ID}",
164+
key_content: "#{FASTLANE_KEY}"
165+
)
166+
167+
def configure_bundle_id(name, identifier, capabilities)
168+
bundle_id = Spaceship::ConnectAPI::BundleId.find(identifier) || Spaceship::ConnectAPI::BundleId.create(name: name, identifier: identifier)
169+
capabilities.each { |capability|
170+
bundle_id.create_capability(capability)
171+
}
172+
end
173+
174+
configure_bundle_id("Loop", "com.#{TEAMID}.loopkit.Loop", [
175+
Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS,
176+
Spaceship::ConnectAPI::BundleIdCapability::Type::HEALTHKIT,
177+
Spaceship::ConnectAPI::BundleIdCapability::Type::PUSH_NOTIFICATIONS,
178+
Spaceship::ConnectAPI::BundleIdCapability::Type::SIRIKIT
179+
])
180+
181+
configure_bundle_id("Loop Intent Extension", "com.#{TEAMID}.loopkit.Loop.Loop-Intent-Extension", [
182+
Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS
183+
])
184+
185+
configure_bundle_id("Loop Status Extension", "com.#{TEAMID}.loopkit.Loop.statuswidget", [
186+
Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS
187+
])
188+
189+
configure_bundle_id("WatchApp", "com.#{TEAMID}.loopkit.Loop.LoopWatch", [])
190+
191+
configure_bundle_id("WatchApp Extension", "com.#{TEAMID}.loopkit.Loop.LoopWatch.watchkitextension", [
192+
Spaceship::ConnectAPI::BundleIdCapability::Type::HEALTHKIT,
193+
Spaceship::ConnectAPI::BundleIdCapability::Type::SIRIKIT
194+
])
195+
196+
configure_bundle_id("Small Status Widget", "com.#{TEAMID}.loopkit.Loop.SmallStatusWidget", [
197+
Spaceship::ConnectAPI::BundleIdCapability::Type::APP_GROUPS
198+
])
199+
200+
end
201+
202+
desc "Provision Certificates"
203+
lane :certs do
204+
setup_ci if ENV['CI']
205+
ENV["MATCH_READONLY"] = false.to_s
206+
207+
app_store_connect_api_key(
208+
key_id: "#{FASTLANE_KEY_ID}",
209+
issuer_id: "#{FASTLANE_ISSUER_ID}",
210+
key_content: "#{FASTLANE_KEY}"
211+
)
212+
213+
match(
214+
type: "appstore",
215+
force: true,
216+
git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}"),
217+
app_identifier: [
218+
"com.#{TEAMID}.loopkit.Loop",
219+
"com.#{TEAMID}.loopkit.Loop.statuswidget",
220+
"com.#{TEAMID}.loopkit.Loop.LoopWatch.watchkitextension",
221+
"com.#{TEAMID}.loopkit.Loop.LoopWatch",
222+
"com.#{TEAMID}.loopkit.Loop.Loop-Intent-Extension",
223+
"com.#{TEAMID}.loopkit.Loop.SmallStatusWidget",
224+
]
225+
)
226+
end
227+
228+
desc "Nuke Certs"
229+
lane :nuke_certs do
230+
setup_ci if ENV['CI']
231+
ENV["MATCH_READONLY"] = false.to_s
232+
233+
app_store_connect_api_key(
234+
key_id: "#{FASTLANE_KEY_ID}",
235+
issuer_id: "#{FASTLANE_ISSUER_ID}",
236+
key_content: "#{FASTLANE_KEY}"
237+
)
238+
239+
match_nuke(
240+
type: "appstore",
241+
team_id: "#{TEAMID}",
242+
skip_confirmation: true,
243+
git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}")
244+
)
245+
end
246+
end

‎fastlane/Matchfile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
GITHUB_REPOSITORY_OWNER ||= ENV["GITHUB_REPOSITORY_OWNER"]
3+
4+
git_url("https://github.com/#{GITHUB_REPOSITORY_OWNER}/Match-Secrets.git")
5+
6+
storage_mode("git")
7+
8+
type("appstore")
9+
10+
# The docs are available on https://docs.fastlane.tools/actions/match

‎fastlane/testflight.md

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Using Github Actions + FastLane to deploy to TestFlight
2+
3+
These instructions allow you to build Loop without having access to a Mac. They also allow you to easily install Loop on phones that are not connected to your computer. So you can send builds and updates to those you care for easily, or have an easy to access backup if you run Loop for yourself. You do not need to worry about correct Xcode/Mac versions either. An app built using this method can easily be deployed to newer versions of iOS, as soon as they are available.
4+
5+
The setup steps are somewhat involved, but nearly all are one time steps. Subsequent builds are trivial.
6+
7+
## Prerequisites.
8+
9+
You don't need much!
10+
11+
* A [github account](https://github.com/signup). The free level comes with plenty of storage and free compute time to build loop, multiple times a day, if you wanted to.
12+
* A paid [Apple Developer account](https://developer.apple.com). You may be able to use the free version, but that has not been tested.
13+
* Some time. Set aside a couple of hours to perform the setup.
14+
15+
16+
## Generate App Store Connect API Key
17+
18+
1. Sign in to the [Apple developer portal page](https://developer.apple.com/account/resources/certificates/list)
19+
1. Copy the team id from the upper right of the screen. Record this as your `TEAMID`
20+
1. Go to the [App Store Connect](https://appstoreconnect.apple.com/access/api) interface, click the "Keys" tab, and create a new key with "Admin" access. Give it a name like "FastLane API Key"
21+
1. Record the key id; this will be used for `FASTLANE_KEY_ID`
22+
1. Record the issuer id; this will be used for `FASTLANE_ISSUER_ID`
23+
1. Download the API key itself, and open it in a text editor. The contents of this file will be used for `FASTLANE_KEY`
24+
25+
## Setup Github
26+
1. Create a new empty repository titled `Match-Secrets`
27+
1. Fork https://github.com/LoopKit/LoopWorkspace into your account.
28+
1. Create a [new personal access token](https://github.com/settings/tokens/new):
29+
* Enter a name for your token. Something like "FastLane Access Token".
30+
* 30 days is fine, or you can select longer if you'd like.
31+
* Select the `repo` permission scope.
32+
* Click "Generate token"
33+
* Copy the token and record it. It will be used below as `GH_PAT`
34+
1. In the forked LoopWorkspace repo, go to Settings -> Secrets -> Actions
35+
1. For each of the following secrets, tap on "New repository secret", then add the name of the secret, along with the value you recorded for it:
36+
* `TEAMID`
37+
* `FASTLANE_KEY_ID`
38+
* `FASTLANE_ISSUER_ID`
39+
* `FASTLANE_KEY`
40+
* `GH_PAT`
41+
* `MATCH_PASSWORD` - just make up a password for this
42+
43+
## Add Identifiers for Loop App
44+
45+
1. Click on the "Actions" tab of your LoopWorkspace repository.
46+
1. Select "Add Identifiers"
47+
1. Click "Run Workflow", and tap the green button.
48+
1. Wait, and within a minute or two you should see a green checkmark indicating the workflow succeeded.
49+
50+
## Create App Group
51+
52+
1. Go to [Register an App Group](https://developer.apple.com/account/resources/identifiers/applicationGroup/add/) on the apple developer site.
53+
1. For Description, use "Loop App Group"
54+
1. For Identifier, enter "group.com.TEAMID.loopkit.LoopGroup", subsituting your team id for `TEAMID`
55+
1. Click "Continue" and then "Register"
56+
57+
## Add App Group to Bundle Identifiers
58+
59+
1. Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list) on the apple developer site.
60+
1. For each of the following identifiers:
61+
* Loop
62+
* Loop Intent Extension
63+
* Loop Status Extension
64+
* Small Status Widget
65+
1. Click on the identifier's name.
66+
1. On the "App Groups" capabilies, click on the "Configure" button.
67+
1. Select the "Loop App Group"
68+
1. Click "Continue".
69+
1. Click "Save".
70+
1. Click "Confirm".
71+
1. Remember to do this for each of the identifiers above.
72+
73+
## Add Time Sensitive Notifications to Loop App ID
74+
1. Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list) on the apple developer site.
75+
1. Click on the "Loop" identifier
76+
1. Scroll down to "Time Sensitive Notifications"
77+
1. Tap the check box to enable Time Sensitive Notifications.
78+
1. Click "Save".
79+
1. Click "Confirm".
80+
1. Remember to do this for each of the identifiers above.
81+
82+
## Create Loop App in App Store Connect
83+
84+
1. Go to the [apps list](https://appstoreconnect.apple.com/apps) on App Store Connect and click the blue "plus" icon to create a New App.
85+
* Select "iOS"
86+
* Select a name: this will have to be unique, so you may have to try a few different names here, but it will not be the name you see on your phone, so it's not that important.
87+
* Select your primary language
88+
* Choose the bundle ID that matches `com.TEAMID.loopkit.Loop`, with TEAMID matching your team id.
89+
* SKU can be anything; e.g. "123"
90+
* Select "Full Access"
91+
* Click Create
92+
* You do not need to fill out the next form. That is for submitting to the app store.
93+
94+
## Create Building Certficates
95+
96+
1. Go back to the "Actions" tab of your LoopWorkspace repository in github.
97+
1. Select "Create Certificates"
98+
1. Click "Run Workflow", and tap the green button.
99+
1. Wait, and within a minute or two you should see a green checkmark indicating the workflow succeeded.
100+
101+
## Build Loop!
102+
103+
1. Click on the "Actions" tab of your LoopWorkspace repository.
104+
1. Select "Build Loop"
105+
1. Click "Run Workflow", select your branch, and tap the green button.
106+
1. You have some time now. Go enjoy a coffee. The build should take about 20-30 minutes.
107+
1. Your app should eventually appear on [App Store Connect](https://appstoreconnect.apple.com/apps)
108+
1. For each phone/person you would like to support Loop on
109+
* Add them in [Users and Access](https://appstoreconnect.apple.com/access/users) on App Store Connect
110+
* Add them to your TestFlight Internal Testing group.

0 commit comments

Comments
 (0)
Please sign in to comment.