build_trio.yml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. name: 4. Build Trio
  2. run-name: Build Trio (${{ github.ref_name }})
  3. on:
  4. workflow_dispatch:
  5. ## Remove the "#" sign from the beginning of the line below to get automated builds on push (code changes in your repository)
  6. #push:
  7. schedule:
  8. - cron: "0 8 * * 3" # Checks for updates at 08:00 UTC every Wednesday
  9. - cron: "0 6 1 * *" # Builds the app on the 1st of every month at 06:00 UTC
  10. env:
  11. UPSTREAM_REPO: nightscout/Trio
  12. UPSTREAM_BRANCH: ${{ github.ref_name }} # branch on upstream repository to sync from (replace with specific branch name if needed)
  13. TARGET_BRANCH: ${{ github.ref_name }} # target branch on fork to be kept in sync, and target branch on upstream to be kept alive (replace with specific branch name if needed)
  14. ALIVE_BRANCH_MAIN: alive-main
  15. ALIVE_BRANCH_DEV: alive-dev
  16. jobs:
  17. # Checks if Distribution certificate is present and valid, optionally nukes and
  18. # creates new certs if the repository variable ENABLE_NUKE_CERTS == 'true'
  19. check_certs:
  20. name: Check certificates
  21. uses: ./.github/workflows/create_certs.yml
  22. secrets: inherit
  23. # Checks if GH_PAT holds workflow permissions
  24. # Checks for existence of alive branch; if non-existent creates it
  25. check_alive_and_permissions:
  26. needs: check_certs
  27. runs-on: ubuntu-latest
  28. name: Check alive branch and permissions
  29. permissions:
  30. contents: write
  31. outputs:
  32. WORKFLOW_PERMISSION: ${{ steps.workflow-permission.outputs.has_permission }}
  33. steps:
  34. - name: Check for workflow permissions
  35. id: workflow-permission
  36. env:
  37. TOKEN_TO_CHECK: ${{ secrets.GH_PAT }}
  38. run: |
  39. PERMISSIONS=$(curl -sS -f -I -H "Authorization: token ${{ env.TOKEN_TO_CHECK }}" https://api.github.com | grep ^x-oauth-scopes: | cut -d' ' -f2-);
  40. if [[ $PERMISSIONS =~ "workflow" || $PERMISSIONS == "" ]]; then
  41. echo "GH_PAT holds workflow permissions or is fine-grained PAT."
  42. echo "has_permission=true" >> $GITHUB_OUTPUT # Set WORKFLOW_PERMISSION to false.
  43. else
  44. echo "GH_PAT lacks workflow permissions."
  45. echo "Automated build features will be skipped!"
  46. echo "has_permission=false" >> $GITHUB_OUTPUT # Set WORKFLOW_PERMISSION to false.
  47. fi
  48. - name: Check for alive branches
  49. if: steps.workflow-permission.outputs.has_permission == 'true'
  50. env:
  51. GITHUB_TOKEN: ${{ secrets.GH_PAT }}
  52. run: |
  53. if [[ $(gh api -H "Accept: application/vnd.github+json" /repos/${{ github.repository_owner }}/Trio/branches | jq --raw-output '[.[] | select(.name == "alive-main" or .name == "alive-dev")] | length > 0') == "true" ]]; then
  54. echo "Branches 'alive-main' or 'alive-dev' exist."
  55. echo "ALIVE_BRANCH_EXISTS=true" >> $GITHUB_ENV
  56. else
  57. echo "Branches 'alive-main' and 'alive-dev' do not exist."
  58. echo "ALIVE_BRANCH_EXISTS=false" >> $GITHUB_ENV
  59. fi
  60. - name: Create alive branches
  61. if: env.ALIVE_BRANCH_EXISTS == 'false'
  62. env:
  63. GITHUB_TOKEN: ${{ secrets.GH_PAT }}
  64. run: |
  65. # Get ref for UPSTREAM_REPO:main
  66. SHA_MAIN=$(curl -sS -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/${{ env.UPSTREAM_REPO }}/git/refs/heads/main | jq -r '.object.sha')
  67. # Get ref for UPSTREAM_REPO:dev
  68. SHA_DEV=$(curl -sS -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/${{ env.UPSTREAM_REPO }}/git/refs/heads/dev | jq -r '.object.sha')
  69. # Create alive-main branch in Trio fork based on UPSTREAM_REPO:main
  70. gh api \
  71. --method POST \
  72. -H "Authorization: token $GITHUB_TOKEN" \
  73. -H "Accept: application/vnd.github.v3+json" \
  74. /repos/${{ github.repository_owner }}/Trio/git/refs \
  75. -f ref='refs/heads/alive-main' \
  76. -f sha=$SHA_MAIN
  77. # Create alive-dev branch in Trio fork based on UPSTREAM_REPO:dev
  78. gh api \
  79. --method POST \
  80. -H "Authorization: token $GITHUB_TOKEN" \
  81. -H "Accept: application/vnd.github.v3+json" \
  82. /repos/${{ github.repository_owner }}/Trio/git/refs \
  83. -f ref='refs/heads/alive-dev' \
  84. -f sha=$SHA_DEV
  85. # Checks for changes in upstream repository; if changes exist prompts sync for build
  86. # Performs keepalive to avoid stale fork
  87. check_latest_from_upstream:
  88. needs: [check_certs, check_alive_and_permissions]
  89. runs-on: ubuntu-latest
  90. name: Check upstream and keep alive
  91. outputs:
  92. NEW_COMMITS: ${{ steps.sync.outputs.has_new_commits }}
  93. ABORT_SYNC: ${{ steps.check_branch.outputs.ABORT_SYNC }}
  94. steps:
  95. - name: Check if running on main or dev branch
  96. if: |
  97. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  98. (vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
  99. id: check_branch
  100. run: |
  101. if [ "${GITHUB_REF##*/}" = "main" ]; then
  102. echo "Running on main branch"
  103. echo "ALIVE_BRANCH=${ALIVE_BRANCH_MAIN}" >> $GITHUB_OUTPUT
  104. echo "ABORT_SYNC=false" >> $GITHUB_OUTPUT
  105. elif [ "${GITHUB_REF##*/}" = "dev" ]; then
  106. echo "Running on dev branch"
  107. echo "ALIVE_BRANCH=${ALIVE_BRANCH_DEV}" >> $GITHUB_OUTPUT
  108. echo "ABORT_SYNC=false" >> $GITHUB_OUTPUT
  109. else
  110. echo "Not running on main or dev branch"
  111. echo "ABORT_SYNC=true" >> $GITHUB_OUTPUT
  112. fi
  113. - name: Checkout target repo
  114. if: |
  115. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  116. (vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
  117. uses: actions/checkout@v4
  118. with:
  119. token: ${{ secrets.GH_PAT }}
  120. ref: ${{ steps.check_branch.outputs.ALIVE_BRANCH }}
  121. - name: Sync upstream changes
  122. if: | # do not run the upstream sync action on the upstream repository
  123. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  124. vars.SCHEDULED_SYNC != 'false' && github.repository_owner != 'nightscout' && steps.check_branch.outputs.ABORT_SYNC == 'false'
  125. id: sync
  126. uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
  127. with:
  128. target_sync_branch: ${{ steps.check_branch.outputs.ALIVE_BRANCH }}
  129. shallow_since: 6 months ago
  130. target_repo_token: ${{ secrets.GH_PAT }}
  131. upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
  132. upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
  133. # Display a sample message based on the sync output var 'has_new_commits'
  134. - name: New commits found
  135. if: |
  136. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  137. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'true'
  138. run: echo "New commits were found to sync."
  139. - name: No new commits
  140. if: |
  141. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  142. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false'
  143. run: echo "There were no new commits."
  144. - name: Show value of 'has_new_commits'
  145. if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' && vars.SCHEDULED_SYNC != 'false' && steps.check_branch.outputs.ABORT_SYNC == 'false'
  146. run: |
  147. echo ${{ steps.sync.outputs.has_new_commits }}
  148. echo "NEW_COMMITS=${{ steps.sync.outputs.has_new_commits }}" >> $GITHUB_OUTPUT
  149. # Keep repository "alive": add empty commits to ALIVE_BRANCH after "time_elapsed" days of inactivity to avoid inactivation of scheduled workflows
  150. - name: Keep alive
  151. if: |
  152. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  153. (vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
  154. uses: gautamkrishnar/keepalive-workflow@v1 # using the workflow with default settings
  155. with:
  156. time_elapsed: 20 # Time elapsed from the previous commit to trigger a new automated commit (in days)
  157. - name: Show scheduled build configuration message
  158. if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION != 'true'
  159. run: |
  160. echo "### :calendar: Scheduled Sync and Build Disabled :mobile_phone_off:" >> $GITHUB_STEP_SUMMARY
  161. echo "You have not yet configured the scheduled sync and build for Trio's browser build." >> $GITHUB_STEP_SUMMARY
  162. echo "Synchronizing your fork of <code>Trio</code> with the upstream repository <code>nightscout/Trio</code> will be skipped." >> $GITHUB_STEP_SUMMARY
  163. echo "If you want to enable automatic builds and updates for your Trio, please follow the instructions \
  164. under the following path <code>Trio/fastlane/testflight.md</code>." >> $GITHUB_STEP_SUMMARY
  165. # Builds Trio
  166. build:
  167. name: Build
  168. needs: [check_certs, check_alive_and_permissions, check_latest_from_upstream]
  169. runs-on: macos-15
  170. permissions:
  171. contents: write
  172. if:
  173. | # runs if started manually, or if sync schedule is set and enabled and scheduled on the first Saturday each month, or if sync schedule is set and enabled and new commits were found
  174. github.event_name == 'workflow_dispatch' ||
  175. (needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  176. (vars.SCHEDULED_BUILD != 'false' && github.event.schedule == '0 6 1 * *') ||
  177. (vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.NEW_COMMITS == 'true' )
  178. )
  179. steps:
  180. - name: Select Xcode version
  181. run: "sudo xcode-select --switch /Applications/Xcode_16.3.app/Contents/Developer"
  182. - name: Checkout Repo for syncing
  183. if: |
  184. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  185. vars.SCHEDULED_SYNC != 'false'
  186. uses: actions/checkout@v4
  187. with:
  188. token: ${{ secrets.GH_PAT }}
  189. ref: ${{ env.TARGET_BRANCH }}
  190. - name: Sync upstream changes
  191. if: | # do not run the upstream sync action on the upstream repository
  192. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  193. vars.SCHEDULED_SYNC != 'false' && github.repository_owner != 'nightscout' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  194. id: sync
  195. uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
  196. with:
  197. target_sync_branch: ${{ env.TARGET_BRANCH }}
  198. shallow_since: 6 months ago
  199. target_repo_token: ${{ secrets.GH_PAT }}
  200. upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
  201. upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
  202. # Display a sample message based on the sync output var 'has_new_commits'
  203. - name: New commits found
  204. if: |
  205. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  206. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'true' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  207. run: echo "New commits were found to sync."
  208. - name: No new commits
  209. if: |
  210. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  211. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  212. run: echo "There were no new commits."
  213. - name: Show value of 'has_new_commits'
  214. if: |
  215. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true'
  216. && vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  217. run: |
  218. echo ${{ steps.sync.outputs.has_new_commits }}
  219. echo "NEW_COMMITS=${{ steps.sync.outputs.has_new_commits }}" >> $GITHUB_OUTPUT
  220. - name: Checkout Repo for building
  221. uses: actions/checkout@v4
  222. with:
  223. token: ${{ secrets.GH_PAT }}
  224. submodules: recursive
  225. ref: ${{ env.TARGET_BRANCH }}
  226. # Customize Trio: Use patches or download and apply patches from GitHub
  227. - name: Customize Trio
  228. run: |
  229. # Trio workspace patches
  230. # -applies any patches located in the Trio/patches/ directory
  231. if $(ls ./patches/* &> /dev/null); then
  232. git apply ./patches/* --allow-empty -v --whitespace=fix
  233. fi
  234. # Download and apply Trio patches from GitHub:
  235. # Template for customizing Trio code (as opposed to submodule code)
  236. # Remove the "#" sign from the beginning of the line below to activate
  237. # and then replace the alphanumeric string with your SHA, this SHA is NOT valid
  238. #curl https://github.com/nightscout/Trio/commit/d206432b024279ef710df462b20bd464cd9682d4.patch | git apply -v --whitespace=fix
  239. # Download and apply Submodule patches from GitHub:
  240. # Template for customizing submodules (you must edit the submodule name)
  241. # This example is for G7SensorKit showing you can apply multiple commits, in the proper order
  242. # Remove the "#" sign from the beginning of the lines below to activate
  243. # This example applies 3 commits from the scan-fix folder; valid only when these are not already in Trio
  244. #curl https://github.com/loopandlearn/G7SensorKit/commit/ba44beb3d1491c453f4f438443c3f8ba29146ab3.patch | git apply --directory=G7SensorKit -v --whitespace=fix
  245. #curl https://github.com/loopandlearn/G7SensorKit/commit/d86ac8e9cd523d1267587dd70c96597125eef7ab.patch | git apply --directory=G7SensorKit -v --whitespace=fix
  246. #curl https://github.com/loopandlearn/G7SensorKit/commit/205054e7537723c2aec58d807634b4853f687244.patch | git apply --directory=G7SensorKit -v --whitespace=fix
  247. # Add patches for additional customization by following the templates above,
  248. # and make sure to specify the submodule by setting "--directory=(submodule_name)".
  249. # Several patches may be added per submodule.
  250. # Adding comments (#) is strongly recommended to easily tell the individual patches apart.
  251. # Patch Fastlane Match to not print tables
  252. - name: Patch Match Tables
  253. run: |
  254. TABLE_PRINTER_PATH=$(ruby -e 'puts Gem::Specification.find_by_name("fastlane").gem_dir')/match/lib/match/table_printer.rb
  255. if [ -f "$TABLE_PRINTER_PATH" ]; then
  256. sed -i "" "/puts(Terminal::Table.new(params))/d" "$TABLE_PRINTER_PATH"
  257. else
  258. echo "table_printer.rb not found"
  259. exit 1
  260. fi
  261. # Install project dependencies
  262. - name: Install Project Dependencies
  263. run: bundle install
  264. # Sync the GitHub runner clock with the Windows time server (workaround as suggested in https://github.com/actions/runner/issues/2996)
  265. - name: Sync clock
  266. run: sudo sntp -sS time.windows.com
  267. # Build signed Trio IPA file
  268. - name: Fastlane Build & Archive
  269. run: bundle exec fastlane build_trio
  270. env:
  271. TEAMID: ${{ secrets.TEAMID }}
  272. GH_PAT: ${{ secrets.GH_PAT }}
  273. FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
  274. FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
  275. FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
  276. MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
  277. # Upload to TestFlight
  278. - name: Fastlane upload to TestFlight
  279. run: bundle exec fastlane release
  280. env:
  281. TEAMID: ${{ secrets.TEAMID }}
  282. GH_PAT: ${{ secrets.GH_PAT }}
  283. FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
  284. FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
  285. FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
  286. MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
  287. # Upload Build artifacts
  288. - name: Upload build log, IPA and Symbol artifacts
  289. if: always()
  290. uses: actions/upload-artifact@v4
  291. with:
  292. name: build-artifacts
  293. path: |
  294. artifacts
  295. buildlog