Skip to content

Build LoopFollow (export-settings) #53

Build LoopFollow (export-settings)

Build LoopFollow (export-settings) #53

name: 4. Build LoopFollow
run-name: Build LoopFollow (${{ github.ref_name }})
on:
workflow_dispatch:
schedule:
# Check for updates every Sunday
# Later logic builds if there are updates or if it is the 2nd Sunday of the month
- cron: "17 10 * * 0" # Sunday at UTC 10:17
env:
UPSTREAM_REPO: loopandlearn/LoopFollow
UPSTREAM_BRANCH: ${{ github.ref_name }} # branch on upstream repository to sync from (replace with specific branch name if needed)
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)
ALIVE_BRANCH_MAIN: alive-main
ALIVE_BRANCH_DEV: alive-dev
jobs:
# Set a logic flag if this is the second instance of this day-of-week in this month
day_in_month:
runs-on: ubuntu-latest
name: Check day in month
outputs:
IS_SECOND_IN_MONTH: ${{ steps.date-check.outputs.is_second_instance }}
steps:
- id: date-check
name: Check if this is the second time this day-of-week happens this month
run: |
DAY_OF_MONTH=$(date +%-d)
WEEK_OF_MONTH=$(( ($(date +%-d) - 1) / 7 + 1 ))
if [[ $WEEK_OF_MONTH -eq 2 ]]; then
echo "is_second_instance=true" >> "$GITHUB_OUTPUT"
else
echo "is_second_instance=false" >> "$GITHUB_OUTPUT"
fi
# Checks if Distribution certificate is present and valid, optionally nukes and
# creates new certs if the repository variable ENABLE_NUKE_CERTS == 'true'
check_certs:
name: Check certificates
uses: ./.github/workflows/create_certs.yml
secrets: inherit
# Checks if GH_PAT holds workflow permissions
# Checks for existence of alive branch; if non-existent creates it
check_alive_and_permissions:
needs: check_certs
runs-on: ubuntu-latest
name: Check alive branch and permissions
permissions:
contents: write
outputs:
WORKFLOW_PERMISSION: ${{ steps.workflow-permission.outputs.has_permission }}
steps:
- name: Check for workflow permissions
id: workflow-permission
env:
TOKEN_TO_CHECK: ${{ secrets.GH_PAT }}
run: |
PERMISSIONS=$(curl -sS -f -I -H "Authorization: token ${{ env.TOKEN_TO_CHECK }}" https://api.github.com | grep ^x-oauth-scopes: | cut -d' ' -f2-);
if [[ $PERMISSIONS =~ "workflow" || $PERMISSIONS == "" ]]; then
echo "GH_PAT holds workflow permissions or is fine-grained PAT."
echo "has_permission=true" >> $GITHUB_OUTPUT # Set WORKFLOW_PERMISSION to false.
else
echo "GH_PAT lacks workflow permissions."
echo "Automated build features will be skipped!"
echo "has_permission=false" >> $GITHUB_OUTPUT # Set WORKFLOW_PERMISSION to false.
fi
- name: Check for alive branches
if: steps.workflow-permission.outputs.has_permission == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
run: |
if [[ $(gh api -H "Accept: application/vnd.github+json" /repos/${{ github.repository_owner }}/LoopFollow/branches | jq --raw-output '[.[] | select(.name == "alive-main" or .name == "alive-dev")] | length > 0') == "true" ]]; then
echo "Branches 'alive-main' or 'alive-dev' exist."
echo "ALIVE_BRANCH_EXISTS=true" >> $GITHUB_ENV
else
echo "Branches 'alive-main' and 'alive-dev' do not exist."
echo "ALIVE_BRANCH_EXISTS=false" >> $GITHUB_ENV
fi
- name: Create alive branches
if: env.ALIVE_BRANCH_EXISTS == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
run: |
# Get ref for UPSTREAM_REPO:main
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')
# Get ref for UPSTREAM_REPO:dev
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')
# Create alive-main branch in LoopFollow fork based on UPSTREAM_REPO:main
gh api \
--method POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
/repos/${{ github.repository_owner }}/LoopFollow/git/refs \
-f ref='refs/heads/alive-main' \
-f sha=$SHA_MAIN
# Create alive-dev branch in LoopFollow fork based on UPSTREAM_REPO:dev
gh api \
--method POST \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
/repos/${{ github.repository_owner }}/LoopFollow/git/refs \
-f ref='refs/heads/alive-dev' \
-f sha=$SHA_DEV
# Checks for changes in upstream repository; if changes exist prompts sync for build
# Performs keepalive to avoid stale fork
check_latest_from_upstream:
needs: [check_certs, check_alive_and_permissions]
runs-on: ubuntu-latest
name: Check upstream and keep alive
outputs:
NEW_COMMITS: ${{ steps.sync.outputs.has_new_commits }}
ABORT_SYNC: ${{ steps.check_branch.outputs.ABORT_SYNC }}
steps:
- name: Check if running on main or dev branch
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
(vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
id: check_branch
run: |
if [ "${GITHUB_REF##*/}" = "main" ]; then
echo "Running on main branch"
echo "ALIVE_BRANCH=${ALIVE_BRANCH_MAIN}" >> $GITHUB_OUTPUT
echo "ABORT_SYNC=false" >> $GITHUB_OUTPUT
elif [ "${GITHUB_REF##*/}" = "dev" ]; then
echo "Running on dev branch"
echo "ALIVE_BRANCH=${ALIVE_BRANCH_DEV}" >> $GITHUB_OUTPUT
echo "ABORT_SYNC=false" >> $GITHUB_OUTPUT
else
echo "Not running on main or dev branch"
echo "ABORT_SYNC=true" >> $GITHUB_OUTPUT
fi
- name: Checkout target repo
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
(vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
ref: ${{ steps.check_branch.outputs.ALIVE_BRANCH }}
- name: Sync upstream changes
if: | # do not run the upstream sync action on the upstream repository
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && github.repository_owner != 'loopandlearn' && steps.check_branch.outputs.ABORT_SYNC == 'false'
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
with:
target_sync_branch: ${{ steps.check_branch.outputs.ALIVE_BRANCH }}
shallow_since: 6 months ago
target_repo_token: ${{ secrets.GH_PAT }}
upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
# Display a sample message based on the sync output var 'has_new_commits'
- name: New commits found
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'true'
run: echo "New commits were found to sync."
- name: No new commits
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false'
run: echo "There were no new commits."
- name: Show value of 'has_new_commits'
if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' && vars.SCHEDULED_SYNC != 'false' && steps.check_branch.outputs.ABORT_SYNC == 'false'
run: |
echo ${{ steps.sync.outputs.has_new_commits }}
echo "NEW_COMMITS=${{ steps.sync.outputs.has_new_commits }}" >> $GITHUB_OUTPUT
# Keep repository "alive": add empty commits to ALIVE_BRANCH after "time_elapsed" days of inactivity to avoid inactivation of scheduled workflows
- name: Keep alive
run: |
echo "Keep Alive is no longer available"
# if: |
# needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
# (vars.SCHEDULED_BUILD != 'false' || vars.SCHEDULED_SYNC != 'false')
# uses: gautamkrishnar/keepalive-workflow@v1 # using the workflow with default settings
# with:
# time_elapsed: 20 # Time elapsed from the previous commit to trigger a new automated commit (in days)
- name: Show scheduled build configuration message
if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION != 'true'
run: |
echo "### :calendar: Scheduled Sync and Build Disabled :mobile_phone_off:" >> $GITHUB_STEP_SUMMARY
echo "You have not yet configured the scheduled sync and build for LoopFollow's browser build." >> $GITHUB_STEP_SUMMARY
echo "Synchronizing your fork of <code>LoopFollow</code> with the upstream repository <code>loopandlearn/LoopFollow</code> will be skipped." >> $GITHUB_STEP_SUMMARY
echo "If you want to enable automatic builds and updates for your LoopFollow, please follow the instructions \
under the following path <code>LoopFollow/fastlane/testflight.md</code>." >> $GITHUB_STEP_SUMMARY
# Builds LoopFollow
build:
name: Build
needs: [check_certs, check_alive_and_permissions, check_latest_from_upstream, day_in_month]
runs-on: macos-15
permissions:
contents: write
if:
| # builds with manual start; if automatic: once a month or when new commits are found
github.event_name == 'workflow_dispatch' ||
(needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
(vars.SCHEDULED_BUILD != 'false' && needs.day_in_month.outputs.IS_SECOND_IN_MONTH == 'true') ||
(vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.NEW_COMMITS == 'true' )
)
steps:
- name: Select Xcode version
run: "sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer"
- name: Checkout Repo for syncing
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false'
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
ref: ${{ env.TARGET_BRANCH }}
- name: Sync upstream changes
if: | # do not run the upstream sync action on the upstream repository
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && github.repository_owner != 'loopandlearn' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
with:
target_sync_branch: ${{ env.TARGET_BRANCH }}
shallow_since: 6 months ago
target_repo_token: ${{ secrets.GH_PAT }}
upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
# Display a sample message based on the sync output var 'has_new_commits'
- name: New commits found
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'true' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
run: echo "New commits were found to sync."
- name: No new commits
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
run: echo "There were no new commits."
- name: Show value of 'has_new_commits'
if: |
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true'
&& vars.SCHEDULED_SYNC != 'false' && needs.check_latest_from_upstream.outputs.ABORT_SYNC == 'false'
run: |
echo ${{ steps.sync.outputs.has_new_commits }}
echo "NEW_COMMITS=${{ steps.sync.outputs.has_new_commits }}" >> $GITHUB_OUTPUT
- name: Checkout Repo for building
uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT }}
submodules: recursive
ref: ${{ env.TARGET_BRANCH }}
# Patch Fastlane Match to not print tables
- name: Patch Match Tables
run: |
TABLE_PRINTER_PATH=$(ruby -e 'puts Gem::Specification.find_by_name("fastlane").gem_dir')/match/lib/match/table_printer.rb
if [ -f "$TABLE_PRINTER_PATH" ]; then
sed -i "" "/puts(Terminal::Table.new(params))/d" "$TABLE_PRINTER_PATH"
else
echo "table_printer.rb not found"
exit 1
fi
# Install project dependencies
- name: Install Project Dependencies
run: bundle install
# Sync the GitHub runner clock with the Windows time server (workaround as suggested in https://github.com/actions/runner/issues/2996)
- name: Sync clock
run: sudo sntp -sS time.windows.com
# Build signed LoopFollow IPA file
- name: Fastlane Build & Archive
run: bundle exec fastlane build_LoopFollow
env:
TEAMID: ${{ secrets.TEAMID }}
GH_PAT: ${{ secrets.GH_PAT }}
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
# Upload to TestFlight
- name: Fastlane upload to TestFlight
run: bundle exec fastlane release
env:
TEAMID: ${{ secrets.TEAMID }}
GH_PAT: ${{ secrets.GH_PAT }}
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
# Upload Build artifacts
- name: Upload build log, IPA and Symbol artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
artifacts
buildlog