Skip to content

Fastlane

Fastlane #517

Workflow file for this run

name: Fastlane
on:
push:
branches:
- main
tags:
- "v*"
pull_request:
types:
- opened
- reopened
- synchronize
workflow_dispatch: # allow manual run
inputs:
push_to_testflight:
type: boolean
description: Upload to TestFlight
required: true
default: false
push_to_playstore:
type: choice
description: Push to PlayStore
options:
- 'false'
- internal
- beta
- production
required: true
version:
type: string
description: App version (vXX.YY.ZZ)
required: true
default: LATEST
build_piece:
type: string
description: Build piece (last 2 digits of build_no)
required: true
jobs:
configure:
name: Configure
runs-on: ubuntu-latest
outputs:
version: ${{ steps.configure.outputs.version }}
build_no: ${{ steps.configure.outputs.build_no }}
push_to_testflight: ${{ steps.configure.outputs.push_to_testflight }}
push_to_playstore: ${{ steps.configure.outputs.push_to_playstore }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get version from tag (new release)
id: tag_version
run: echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
if: |
github.event_name == 'push' &&
github.event.repository.full_name == github.repository &&
github.ref_type == 'tag'
- name: Get version from last release
id: last_release
uses: pozetroninc/github-action-get-latest-release@master
with:
repository: ${{ github.repository }}
excludes: draft
token: ${{ secrets.GITHUB_TOKEN }}
- name: Gather workflow info
id: configure
run: |
VERSION=""
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# On pull_request event, no need to publish
PUSH_TESTFLIGHT=false
PUSH_PLAYSTORE=false
elif [[ "${{ steps.tag_version.outputs.version }}" != "" ]]; then
# On tag push (release), we're in production
PUSH_TESTFLIGHT=true
PUSH_PLAYSTORE="${{ vars.PLAYSTORE_RELEASE_TRACK }}"
VERSION="${{ steps.tag_version.outputs.version }}"
BUILD_PIECE=0
elif [[ "${{ github.event.inputs.version }}" != "" ]]; then
# On repo manual dispatch
PUSH_TESTFLIGHT="${{ github.event.inputs.push_to_testflight }}"
PUSH_PLAYSTORE="${{ github.event.inputs.push_to_playstore }}"
if [[ "${{ github.event.inputs.version }}" == "LATEST" && "${{ steps.last_release.outputs.release }}" != "" ]]; then
VERSION="${{ steps.last_release.outputs.release }}"
else
VERSION="${{ github.event.inputs.version }}"
fi
BUILD_PIECE="${{ github.event.inputs.build_piece }}"
elif [[ "${{ steps.last_release.outputs.release }}" != "" ]]; then
# we're supposed to be on push on main (e.g. pr merge) here
PUSH_TESTFLIGHT=true
PUSH_PLAYSTORE=beta
VERSION="${{ steps.last_release.outputs.release }}"
BUILD_PIECE=$(git rev-list $VERSION.. --count)
else
echo "UNHANDLED EVENT. CANNOT CONFIG SAFELY."
exit 1
fi
if [[ "$BUILD_PIECE" != "" && ! "$BUILD_PIECE" =~ ^[0-9]{1,2}$ ]]; then
echo "INVALID BUILD PIECE FORMAT: $BUILD_PIECE"
exit 1
fi
if [[ "$VERSION" =~ ^v([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,2})$ ]]; then
MAJOR=${BASH_REMATCH[1]}
MINOR=${BASH_REMATCH[2]}
SUBV=${BASH_REMATCH[3]}
BUILD_NO=$(( MAJOR*1000000 + MINOR*10000 + SUBV*100 + BUILD_PIECE ))
echo "build_no=$BUILD_NO" >> $GITHUB_OUTPUT
echo "version=$MAJOR.$MINOR.$SUBV" >> $GITHUB_OUTPUT
elif [[ "$VERSION" != "" ]]; then
echo "INVALID VERSION FORMAT: $VERSION"
exit 2
fi
echo "push_to_playstore=$PUSH_PLAYSTORE" >> $GITHUB_OUTPUT
echo "push_to_testflight=$PUSH_TESTFLIGHT" >> $GITHUB_OUTPUT
echo "CONFIGURED:"
cat $GITHUB_OUTPUT
- name: Cache node modules
uses: actions/cache@v3
with:
path: ./node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('./package-lock.json') }}
- name: Setup .npmrc
run: printf '@polito:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}\n' > .npmrc
- name: Setup Mapbox
run: |
printf 'MAPBOX_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> .env
printf 'MAPBOX_DOWNLOADS_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> android/local.properties
printf 'machine api.mapbox.com\n\tlogin mapbox\n\tpassword ${{ secrets.MAPBOX_TOKEN }}\n' > ~/.netrc
- name: Install npm dependencies
run: npm install
build-android:
name: ${{ needs.configure.outputs.push_to_playstore == 'false' && 'Build' || 'Build & Deploy' }} Android
needs: configure
runs-on: ubuntu-latest
env:
LANG: en_US.UTF-8
CI: 'true'
BUILD_NO: ${{ needs.configure.outputs.build_no }}
APP_VERSION: ${{ needs.configure.outputs.version }}
SUPPLY_GOOGLE_JSON_PATH: './pc-api-secret.json'
KEYSTORE_PW: ${{ secrets.ANDROID_KEYSTORE_PW }}
KEYSTORE_PATH: './keystore.jks'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v1
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
working-directory: ./android
ruby-version: '2.7.6'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Cache node modules
uses: actions/cache@v3
with:
path: ./node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('./package-lock.json') }}
- name: Cache Gradle artifacts
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Setup .npmrc
run: printf '@polito:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}\n' > .npmrc
- name: Setup Mapbox
run: |
printf 'MAPBOX_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> .env
printf 'MAPBOX_DOWNLOADS_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> android/local.properties
printf 'machine api.mapbox.com\n\tlogin mapbox\n\tpassword ${{ secrets.MAPBOX_TOKEN }}\n' > ~/.netrc
- name: Install npm dependencies
run: npm install
- name: Prepare fastlane
working-directory: ./android
run: |
echo "${{ secrets.SUPPLY_GOOGLE_JSON_SECRET }}" | base64 -d > ${SUPPLY_GOOGLE_JSON_PATH}
echo "${{ secrets.ANDROID_KEYSTORE_B64 }}" | base64 -d > ${KEYSTORE_PATH}
chmod 600 ${KEYSTORE_PATH} ${SUPPLY_GOOGLE_JSON_PATH}
- name: Fastlane VERIFY lane
if: needs.configure.outputs.push_to_playstore == 'false'
working-directory: ./android
run: bundle exec fastlane verify
- name: Fastlane RELEASE lane
if: contains(fromJSON('["internal", "beta", "production"]'), needs.configure.outputs.push_to_playstore)
working-directory: ./android
env:
STORE_TRACK: ${{ needs.configure.outputs.push_to_playstore }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
run: bundle exec fastlane release
- name: Fastlane APK lane
if: |
github.event_name == 'push' &&
github.ref_type == 'tag'
run: bundle exec fastlane apk
working-directory: ./android
- name: Upload Artifacts
if: |
github.event_name == 'push' &&
github.ref_type == 'tag'
uses: actions/upload-artifact@v3
with:
name: android-release
path: android/app/build/outputs/apk/release/*.apk
build-ios:
name: ${{ needs.configure.outputs.push_to_testflight == 'false' && 'Build' || 'Build & Deploy' }} iOS
env:
ImageOS: macos12
LANG: en_US.UTF-8
CI: 'true'
BUILD_NO: ${{ needs.configure.outputs.build_no }}
APP_VERSION: ${{ needs.configure.outputs.version }}
MATCH_PASSWORD: ${{ secrets.FASTLANE_MATCH_KEY }}
MATCH_GIT_PRIVATE_KEY: "./github_access.pk"
FASTLANE_USERNAME: ${{ secrets.FASTLANE_POLI_MOBILE_USER }}
FASTLANE_PASSWORD: ${{ secrets.FASTLANE_POLI_MOBILE_PW }}
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_DEV_PW }}
needs: configure
runs-on: [self-hosted, macos-12]
steps:
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '14'
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
working-directory: ./ios
ruby-version: '2.7.6'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Cache node modules
uses: actions/cache@v3
with:
path: ./node_modules
key: ${{ runner.os }}-npm-${{ hashFiles('./package-lock.json') }}
- name: Setup .npmrc
run: printf '@polito:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}\n' > .npmrc
- name: Setup Mapbox
run: |
printf 'MAPBOX_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> .env
printf 'MAPBOX_DOWNLOADS_TOKEN=${{ secrets.MAPBOX_TOKEN }}\n' >> android/local.properties
printf 'machine api.mapbox.com\n\tlogin mapbox\n\tpassword ${{ secrets.MAPBOX_TOKEN }}\n' > ~/.netrc
- name: Install npm dependencies
run: npm install
- name: Cache pods
uses: actions/cache@v3
with:
path: ./ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
- name: Install pod dependencies
working-directory: ./ios
run: bundle exec pod install --repo-update
- name: Prepare fastlane
working-directory: ./ios
run: |
echo "${{ secrets.MATCH_GIT_AUTH_PK }}" > ${MATCH_GIT_PRIVATE_KEY}
chmod 600 ${MATCH_GIT_PRIVATE_KEY}
- name: Fastlane VERIFY lane
if: needs.configure.outputs.push_to_testflight == 'false'
working-directory: ./ios
run: |
bundle exec fastlane verify
- name: Fastlane RELEASE lane
if: needs.configure.outputs.push_to_testflight == 'true'
working-directory: ./ios
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
run: |
bundle exec fastlane release
create-release:
name: Create GitHub Release
permissions:
contents: write
if: |
github.event_name == 'push' &&
github.event.repository.full_name == github.repository &&
github.ref_type == 'tag'
needs: [build-android, build-ios]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Gather artifacts
uses: actions/download-artifact@v3
with:
name: android-release
path: ./android-release
- name: Create release
uses: ncipollo/release-action@v1
with:
generateReleaseNotes: true
skipIfReleaseExists: true
artifacts: ./android-release/*.apk