build_trio.yml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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:
  169. [check_certs, check_alive_and_permissions, check_latest_from_upstream]
  170. runs-on: macos-15
  171. permissions:
  172. contents: write
  173. if:
  174. | # 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
  175. github.event_name == 'workflow_dispatch' ||
  176. (needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  177. (vars.SCHEDULED_BUILD != 'false' && github.event.schedule == '0 6 1 * *') ||
  178. (vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.NEW_COMMITS == 'true' )
  179. )
  180. steps:
  181. - name: Select Xcode version
  182. run: "sudo xcode-select --switch /Applications/Xcode_16.0.app/Contents/Developer"
  183. - name: Checkout Repo for syncing
  184. if: |
  185. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  186. vars.SCHEDULED_SYNC != 'false'
  187. uses: actions/checkout@v4
  188. with:
  189. token: ${{ secrets.GH_PAT }}
  190. ref: ${{ env.TARGET_BRANCH }}
  191. - name: Sync upstream changes
  192. if: | # do not run the upstream sync action on the upstream repository
  193. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  194. vars.SCHEDULED_SYNC != 'false' && github.repository_owner != 'nightscout' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  195. id: sync
  196. uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
  197. with:
  198. target_sync_branch: ${{ env.TARGET_BRANCH }}
  199. shallow_since: 6 months ago
  200. target_repo_token: ${{ secrets.GH_PAT }}
  201. upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
  202. upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
  203. # Display a sample message based on the sync output var 'has_new_commits'
  204. - name: New commits found
  205. if: |
  206. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  207. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'true' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  208. run: echo "New commits were found to sync."
  209. - name: No new commits
  210. if: |
  211. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
  212. vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  213. run: echo "There were no new commits."
  214. - name: Show value of 'has_new_commits'
  215. if: |
  216. needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true'
  217. && vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
  218. run: |
  219. echo ${{ steps.sync.outputs.has_new_commits }}
  220. echo "NEW_COMMITS=${{ steps.sync.outputs.has_new_commits }}" >> $GITHUB_OUTPUT
  221. - name: Checkout Repo for building
  222. uses: actions/checkout@v4
  223. with:
  224. token: ${{ secrets.GH_PAT }}
  225. submodules: recursive
  226. ref: ${{ env.TARGET_BRANCH }}
  227. # Patch Fastlane Match to not print tables
  228. - name: Patch Match Tables
  229. run: |
  230. TABLE_PRINTER_PATH=$(ruby -e 'puts Gem::Specification.find_by_name("fastlane").gem_dir')/match/lib/match/table_printer.rb
  231. if [ -f "$TABLE_PRINTER_PATH" ]; then
  232. sed -i "" "/puts(Terminal::Table.new(params))/d" "$TABLE_PRINTER_PATH"
  233. else
  234. echo "table_printer.rb not found"
  235. exit 1
  236. fi
  237. # Install project dependencies
  238. - name: Install Project Dependencies
  239. run: bundle install
  240. # Sync the GitHub runner clock with the Windows time server (workaround as suggested in https://github.com/actions/runner/issues/2996)
  241. - name: Sync clock
  242. run: sudo sntp -sS time.windows.com
  243. # Build signed Trio IPA file
  244. - name: Fastlane Build & Archive
  245. run: bundle exec fastlane build_trio
  246. env:
  247. TEAMID: ${{ secrets.TEAMID }}
  248. GH_PAT: ${{ secrets.GH_PAT }}
  249. FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
  250. FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
  251. FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
  252. MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
  253. # Upload to TestFlight
  254. - name: Fastlane upload to TestFlight
  255. run: bundle exec fastlane release
  256. env:
  257. TEAMID: ${{ secrets.TEAMID }}
  258. GH_PAT: ${{ secrets.GH_PAT }}
  259. FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
  260. FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
  261. FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
  262. MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
  263. # Upload Build artifacts
  264. - name: Upload build log, IPA and Symbol artifacts
  265. if: always()
  266. uses: actions/upload-artifact@v4
  267. with:
  268. name: build-artifacts
  269. path: |
  270. artifacts
  271. buildlog