CI #19
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
on: | |
pull_request: | |
workflow_dispatch: | |
inputs: | |
build_ios: | |
type: boolean | |
default: false | |
description: | | |
Whether or not to build for iOS. | |
This setting has no effect if `release` is true. | |
Note! iOS builds cost 10x more CI minutes since a mac runner is required. | |
release: | |
type: boolean | |
default: false | |
description: | | |
Create a new release. | |
This will create a preview release for non-main branches and a full release on `main`. | |
env: | |
FLUTTER_VERSION: 3.16.x | |
NODE_VERSION: 20 | |
YQ_VERSION: v4.40.5 | |
jobs: | |
calculate_version: | |
name: Calculate Version | |
runs-on: ubuntu-latest | |
outputs: | |
version_name: ${{ steps.version-name.outputs.version_name }} | |
version_code: ${{ steps.version-code.outputs.version_code }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- uses: chrisdickinson/setup-yq@latest | |
with: | |
yq-version: ${{ env.YQ_VERSION }} | |
- name: Add Current Branch to .releaserc.yml | |
if: ${{ !contains(fromJSON('["main"]'), github.ref_name) }} | |
run: | | |
yq --inplace '. *+ {"branches": [{"name": "${{ github.ref_name }}", "prerelease": "dev"}]}' .releaserc.yml | |
- name: Calculate Version Name | |
id: version-name | |
run: | | |
npm i semantic-release @semantic-release/commit-analyzer @semantic-release/release-notes-generator conventional-changelog-conventionalcommits @semantic-release/exec | |
yq --inplace '.plugins += [["@semantic-release/exec", {"verifyReleaseCmd": "echo \"version_name=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\""}]]' .releaserc.yml | |
npx --yes semantic-release --dry-run ${{ runner.debug && '--debug' || '' }} | |
- name: Calculate Version Code | |
id: version-code | |
# Version code changes every minute. | |
# This should last us ~3960 years | |
run: echo "version_code=$(bc <<< "$(date -u +'%s') / 60 - 1705195260 / 60")" >> "$GITHUB_OUTPUT" | |
- name: Print Calculated Version | |
run: echo '${{ steps.version-name.outputs.version_name }}+${{ steps.version-code.outputs.version_code }}' | |
verify: | |
name: Verify | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: subosito/flutter-action@v2 | |
with: | |
flutter-version: ${{ env.FLUTTER_VERSION }} | |
channel: stable | |
cache: true | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- name: Validate PR commits with commitlint | |
if: github.event_name == 'pull_request' | |
run: | | |
npm install commitlint conventional-changelog-conventionalcommits | |
npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose | |
- name: Validate code formatting | |
run: dart format --set-exit-if-changed . | |
- name: Perform code analysis | |
run: flutter analyze | |
- name: Run tests | |
run: flutter test | |
build_android: | |
name: Build Android | |
runs-on: ubuntu-latest | |
needs: | |
- calculate_version | |
- verify | |
env: | |
VERSION_NAME: ${{ needs.calculate_version.outputs.version_name }} | |
VERSION_CODE: ${{ needs.calculate_version.outputs.version_code }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: subosito/flutter-action@v2 | |
with: | |
flutter-version: ${{ env.FLUTTER_VERSION }} | |
channel: stable | |
cache: true | |
- uses: chrisdickinson/setup-yq@latest | |
with: | |
yq-version: ${{ env.YQ_VERSION }} | |
- name: Set Release Version | |
run: | | |
echo "Release Version: ${{ env.VERSION_NAME }}+${{ env.VERSION_CODE }}" | |
yq --inplace '.version = "${{ env.VERSION_NAME }}+${{ env.VERSION_CODE }}"' pubspec.yaml | |
- name: Create Production Build | |
run: | | |
flutter build appbundle --obfuscate --split-debug-info=build/app/debug-info | |
flutter build apk --obfuscate --split-per-abi --split-debug-info=build/app/debug-info | |
- name: Upload Build Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: android-artifacts | |
path: | | |
build/app/debug-info/* | |
build/app/outputs/apk/release/* | |
build/app/outputs/bundle/release/* | |
build_ios: | |
name: Build iOS | |
# TODO(FelixZY): Need to configure code signing certificate before iOS can be built. | |
if: false && (inputs.release || inputs.build_ios) | |
runs-on: macos-latest | |
needs: | |
- calculate_version | |
- verify | |
env: | |
VERSION_NAME: ${{ needs.calculate_version.outputs.version_name }} | |
VERSION_CODE: ${{ needs.calculate_version.outputs.version_code }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: subosito/flutter-action@v2 | |
with: | |
flutter-version: ${{ env.FLUTTER_VERSION }} | |
channel: stable | |
cache: true | |
- uses: chrisdickinson/setup-yq@latest | |
with: | |
yq-version: ${{ env.YQ_VERSION }} | |
- name: Set Release Version | |
run: | | |
echo "Release Version: ${{ env.VERSION_NAME }}+${{ env.VERSION_CODE }}" | |
yq --inplace '.version = "${{ env.VERSION_NAME }}+${{ env.VERSION_CODE }}"' pubspec.yaml | |
- name: Install Dependencies | |
run: | | |
flutter precache --ios | |
flutter pub get | |
- name: Create Production Build | |
run: flutter build ipa --obfuscate --split-debug-info=build/ios/debug-info | |
- name: Upload Build Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: ios-artifacts | |
path: build/ios | |
build_web: | |
name: Build Web | |
runs-on: ubuntu-latest | |
needs: | |
- calculate_version | |
- verify | |
env: | |
VERSION_NAME: ${{ needs.calculate_version.outputs.version_name }} | |
VERSION_CODE: ${{ needs.calculate_version.outputs.version_code }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: subosito/flutter-action@v2 | |
with: | |
flutter-version: ${{ env.FLUTTER_VERSION }} | |
channel: stable | |
cache: true | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- name: Create Production Build | |
run: flutter build web | |
- name: Upload Build Artifacts | |
uses: actions/upload-artifact@v4 | |
with: | |
name: web-artifacts | |
path: build/web | |
release_web: | |
name: Create Web Deployment | |
if: inputs.release | |
runs-on: ubuntu-latest | |
needs: | |
- build_web | |
env: | |
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} | |
steps: | |
- name: Download Web Artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
name: web-artifacts | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- name: Install Vercel CLI | |
run: npm install vercel@latest | |
- name: Create Preview Deployment | |
if: github.ref_name != 'main' | |
run: | | |
vercel pull --yes --environment=preview --token=$VERCEL_TOKEN | |
vercel build --token=$VERCEL_TOKEN | |
vercel deploy --prebuilt --token=$VERCEL_TOKEN | |
- name: Create Production Deployment | |
if: github.ref_name == 'main' | |
run: | | |
vercel pull --yes --environment=production --token=$VERCEL_TOKEN | |
vercel build --token=$VERCEL_TOKEN | |
vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN | |
release_github: | |
name: Create GitHub Release | |
if: inputs.release | |
runs-on: ubuntu-latest | |
needs: | |
- build_android | |
# TODO(FelixZY): Need to configure code signing certificate before iOS can be built. | |
#- build_ios | |
- release_web | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Download Web Artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
name: web-artifacts | |
path: build/web | |
- name: Zip Web Artifacts | |
run: | | |
cd build | |
zip -r web.zip web/ | |
- name: Download Android Artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
name: android-artifacts | |
path: build/android | |
- uses: actions/setup-node@v4 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
- uses: chrisdickinson/setup-yq@latest | |
with: | |
yq-version: ${{ env.YQ_VERSION }} | |
- name: Add Current Branch to .releaserc.yml | |
if: ${{ !contains(fromJSON('["main"]'), github.ref_name) }} | |
run: | | |
yq --inplace '. *+ {"branches": [{"name": "${{ github.ref_name }}", "prerelease": "dev"}]}' .releaserc.yml | |
- name: Create GitHub Release | |
id: semantic-release | |
run: | | |
npm i semantic-release @semantic-release/commit-analyzer @semantic-release/release-notes-generator conventional-changelog-conventionalcommits @semantic-release/github | |
yq --inplace '.plugins += [["@semantic-release/github", {"assets": [{"path": "build/web.zip", "label": "Web"}, {"path": "build/android/"}]}]]' .releaserc.yml | |
npx --yes semantic-release ${{ runner.debug && '--debug' || '' }} |