Skip to content

Build main/0.11.1 - 1 #708

Build main/0.11.1 - 1

Build main/0.11.1 - 1 #708

Workflow file for this run

name: Build AppFlowy Application
run-name: Build ${{ github.event.inputs.branch || 'main' }}/${{ github.event.inputs.version || '0.11.1' }} - ${{ github.event.inputs.internal_build || '1' }}
on:
schedule:
# Daily builds at 8 AM SGT (00:00 UTC) and 4 PM SGT (08:00 UTC)
- cron: '0 0 * * *' # 8 AM SGT
- cron: '0 8 * * *' # 4 PM SGT
workflow_dispatch:
inputs:
version:
description: "Release version (e.g., 0.10.7)"
required: true
type: string
default: "0.11.2"
branch:
description: "Source branch for build"
required: true
default: "main"
type: string
platforms:
description: "Platforms to build for"
required: true
type: choice
options:
- "all"
- "android"
- "ios"
- "macos"
- "windows"
- "linux"
- "mobile" # android + ios
- "desktop" # macos + windows + linux
android_build_type:
description: "Android build type"
required: false
type: choice
default: "apk"
options:
- "both"
- "apk"
- "appbundle"
macos_arch:
description: "macOS architecture"
required: false
type: choice
default: "All"
options:
- "All"
internal_build:
description: "Internal build (1 for internal, 0 for external)"
required: false
type: choice
default: "1"
options:
- "0"
- "1"
upload_to_store:
description: "Upload to app stores (not implemented yet)"
required: false
type: boolean
default: false
release_notes:
description: "Custom release notes (optional)"
required: false
type: string
push:
tags:
- "*"
env:
FLUTTER_VERSION: "3.27.4"
RUST_TOOLCHAIN: "1.85.0"
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
skip_build: ${{ steps.parse_inputs.outputs.skip_build }}
version: ${{ steps.parse_inputs.outputs.version }}
release_tag: ${{ steps.parse_inputs.outputs.release_tag }}
branch_name: ${{ steps.parse_inputs.outputs.branch_name }}
build_number: ${{ steps.parse_inputs.outputs.build_number }}
platforms: ${{ steps.parse_inputs.outputs.platforms }}
android_build_type: ${{ steps.parse_inputs.outputs.android_build_type }}
macos_arch: ${{ steps.parse_inputs.outputs.macos_arch }}
internal_build: ${{ steps.parse_inputs.outputs.internal_build }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Parse Inputs
id: parse_inputs
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
# Manual trigger
VERSION="${{ github.event.inputs.version }}"
BRANCH_NAME="${{ github.event.inputs.branch }}"
PLATFORMS="${{ github.event.inputs.platforms }}"
ANDROID_BUILD_TYPE="${{ github.event.inputs.android_build_type }}"
MACOS_ARCH="${{ github.event.inputs.macos_arch }}"
INTERNAL_BUILD="${{ github.event.inputs.internal_build }}"
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
# Scheduled trigger - build all platforms with default settings
VERSION="0.11.2"
BRANCH_NAME="main"
PLATFORMS="all"
ANDROID_BUILD_TYPE="both"
MACOS_ARCH="All"
INTERNAL_BUILD="1"
CURRENT_TIME_SGT=$(TZ='Asia/Singapore' date +"%Y-%m-%d %H:%M:%S %Z")
echo "📅 Scheduled build triggered at $CURRENT_TIME_SGT"
# Check if there are new commits since last scheduled build
# Scheduled builds run at 8 AM and 4 PM SGT (00:00 and 08:00 UTC)
CURRENT_HOUR=$(TZ='Asia/Singapore' date +"%H")
# Get last commit time from source repository
LAST_COMMIT_TIME=$(curl -s \
-H "Authorization: token ${{ secrets.PRIVATE_REPO_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/AppFlowy-IO/AppFlowy-Premium/commits/$BRANCH_NAME" \
| jq -r '.commit.committer.date')
if [ -z "$LAST_COMMIT_TIME" ] || [ "$LAST_COMMIT_TIME" == "null" ]; then
echo "⚠️ Warning: Could not fetch last commit time, proceeding with build..."
else
LAST_COMMIT_TIMESTAMP=$(date -u -d "$LAST_COMMIT_TIME" +%s)
CURRENT_TIMESTAMP=$(date +%s)
# Calculate time difference in hours
TIME_DIFF_HOURS=$(( ($CURRENT_TIMESTAMP - $LAST_COMMIT_TIMESTAMP) / 3600 ))
echo "📝 Last commit time: $LAST_COMMIT_TIME"
echo "⏱️ Time since last commit: ${TIME_DIFF_HOURS} hours"
# If last commit is older than 12 hours, skip build
# This ensures we catch commits made after the previous scheduled build
# (builds run every 8 hours, so 12-hour window provides overlap)
if [ $TIME_DIFF_HOURS -ge 12 ]; then
echo "✅ No new commits in the last 12 hours (last commit: ${TIME_DIFF_HOURS} hours ago)"
echo "⏭️ Skipping build to save resources"
echo "skip_build=true" >> $GITHUB_OUTPUT
exit 0
else
echo "🆕 Found new commits within last 12 hours, proceeding with build"
fi
fi
else
# Tag trigger
TAG_NAME=${GITHUB_REF#refs/tags/}
VERSION=$(echo "$TAG_NAME" | cut -f1 -d"_")
BRANCH_NAME=$(echo "$TAG_NAME" | cut -f2- -d"_")
PLATFORMS="all"
ANDROID_BUILD_TYPE="both"
MACOS_ARCH="All"
INTERNAL_BUILD="1"
if [ -z "$BRANCH_NAME" ]; then
echo "Error: BRANCH_NAME is empty. The tag name should be in the format of <version>_<branch_name>"
exit 1
fi
fi
# Input validation
if [ -z "$VERSION" ]; then
echo "❌ Error: Version cannot be empty"
exit 1
fi
if [ -z "$BRANCH_NAME" ]; then
echo "❌ Error: Branch name cannot be empty"
exit 1
fi
# Validate version format (semantic versioning)
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][a-zA-Z0-9]+)*$ ]]; then
echo "❌ Error: Version must follow semantic versioning format (e.g., 1.0.0, 1.0.0-beta.1)"
exit 1
fi
# Validate platforms
VALID_PLATFORMS=("all" "android" "ios" "macos" "windows" "linux" "mobile" "desktop")
if [[ ! " ${VALID_PLATFORMS[@]} " =~ " ${PLATFORMS} " ]]; then
echo "❌ Error: Invalid platform '$PLATFORMS'. Valid options: ${VALID_PLATFORMS[*]}"
exit 1
fi
# Generate build number from timestamp
BUILD_NUMBER=$(date +%s)
# Generate timestamped release tag in SGT (GMT+8) with branch name
TIMESTAMP=$(TZ='Asia/Singapore' date +"%y%m%d-%H%M")
RELEASE_TAG="${VERSION}-${BRANCH_NAME}-${TIMESTAMP}"
echo "✅ Validation passed!"
echo "📦 Version: $VERSION"
echo "🏷️ Release Tag: $RELEASE_TAG"
echo "🌿 Branch: $BRANCH_NAME"
echo "🚀 Platforms: $PLATFORMS"
echo "🔢 Build Number: $BUILD_NUMBER"
echo "📱 Android Build Type: $ANDROID_BUILD_TYPE"
echo "💻 macOS Architecture: $MACOS_ARCH"
echo "🏗️ Internal Build: $INTERNAL_BUILD"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "release_tag=$RELEASE_TAG" >> $GITHUB_OUTPUT
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
echo "platforms=$PLATFORMS" >> $GITHUB_OUTPUT
echo "android_build_type=$ANDROID_BUILD_TYPE" >> $GITHUB_OUTPUT
echo "macos_arch=$MACOS_ARCH" >> $GITHUB_OUTPUT
echo "internal_build=$INTERNAL_BUILD" >> $GITHUB_OUTPUT
- name: Validate Branch Exists
if: steps.parse_inputs.outputs.skip_build != 'true'
run: |
echo "🔍 Checking if branch '${{ steps.parse_inputs.outputs.branch_name }}' exists..."
# Use GitHub API to check if branch exists (requires token)
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${{ secrets.PRIVATE_REPO_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/AppFlowy-IO/AppFlowy-Premium/branches/${{ steps.parse_inputs.outputs.branch_name }}")
if [ "$HTTP_STATUS" = "200" ]; then
echo "✅ Branch '${{ steps.parse_inputs.outputs.branch_name }}' exists"
elif [ "$HTTP_STATUS" = "404" ]; then
echo "❌ Error: Branch '${{ steps.parse_inputs.outputs.branch_name }}' does not exist in AppFlowy-Premium repository"
exit 1
else
echo "⚠️ Warning: Could not verify branch existence (HTTP $HTTP_STATUS). Proceeding anyway..."
echo "This will be validated during checkout."
fi
- name: Check Required Secrets
if: steps.parse_inputs.outputs.skip_build != 'true'
run: |
echo "🔐 Checking required secrets availability..."
MISSING_SECRETS=()
# Check for basic secrets
if [ -z "${{ secrets.PRIVATE_REPO_TOKEN }}" ]; then
MISSING_SECRETS+=("PRIVATE_REPO_TOKEN")
fi
if [ -z "${{ secrets.ADMIN_GITHUB_TOKEN }}" ]; then
MISSING_SECRETS+=("ADMIN_GITHUB_TOKEN")
fi
# Check platform-specific secrets if needed
if [[ "${{ steps.parse_inputs.outputs.platforms }}" == *"android"* ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "all" ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "mobile" ]]; then
if [ -z "${{ secrets.ANDROID_UPLOAD_KEYSTORE_BASE64 }}" ]; then
MISSING_SECRETS+=("ANDROID_UPLOAD_KEYSTORE_BASE64")
fi
fi
if [[ "${{ steps.parse_inputs.outputs.platforms }}" == *"ios"* ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "all" ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "mobile" ]]; then
if [ -z "${{ secrets.IOS_CERTIFICATE_BASE64 }}" ]; then
MISSING_SECRETS+=("IOS_CERTIFICATE_BASE64")
fi
fi
if [[ "${{ steps.parse_inputs.outputs.platforms }}" == *"macos"* ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "all" ]] || [[ "${{ steps.parse_inputs.outputs.platforms }}" == "desktop" ]]; then
if [ -z "${{ secrets.MACOS_CERTIFICATE_BASE64 }}" ]; then
echo "⚠️ Warning: MACOS_CERTIFICATE_BASE64 not set. macOS builds will not be code signed."
fi
fi
if [ ${#MISSING_SECRETS[@]} -ne 0 ]; then
echo "❌ Error: Missing required secrets: ${MISSING_SECRETS[*]}"
echo "Please configure these secrets in the repository settings."
exit 1
fi
echo "✅ All required secrets are available"
- name: Checkout source code
if: steps.parse_inputs.outputs.skip_build != 'true'
uses: actions/checkout@v3
with:
repository: AppFlowy-IO/AppFlowy-Premium
ref: ${{ steps.parse_inputs.outputs.branch_name }}
token: ${{ secrets.PRIVATE_REPO_TOKEN }}
fetch-depth: 0
- name: Create release notes
if: steps.parse_inputs.outputs.skip_build != 'true'
id: create_release_notes
run: |
BUILD_TIME_SGT=$(TZ='Asia/Singapore' date +"%Y-%m-%d %H:%M:%S %Z")
COMMITS=$(git log -5 --pretty=format:"- %h - %s (%an)" || echo "No commits available")
ADDITIONAL_NOTES=""
if [[ "${{ github.event.inputs.release_notes }}" != "" ]]; then
ADDITIONAL_NOTES="${{ github.event.inputs.release_notes }}"
fi
RELEASE_NOTES=$(cat <<EOF
# Release ${{ steps.parse_inputs.outputs.version }}
**Branch:** ${{ steps.parse_inputs.outputs.branch_name }}
**Build Time (SGT/GMT+8):** ${BUILD_TIME_SGT}
**Triggered By:** @${{ github.actor }}
**Build Number:** ${{ steps.parse_inputs.outputs.build_number }}
**Platforms:** ${{ steps.parse_inputs.outputs.platforms }}
---
## What's Changed
### Recent Commits
${COMMITS}
${ADDITIONAL_NOTES:+### Additional Notes}
${ADDITIONAL_NOTES}
---
### Build Artifacts
- Android APK/AAB: Available for download
- iOS IPA: Available for download
- macOS DMG: Available for download
- Windows EXE: Available for download
- Linux AppImage: Available for download
*Note: Only artifacts for the selected platforms will be available.*
EOF
)
echo "release_notes<<EOF" >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
shell: bash
- name: Create release
if: steps.parse_inputs.outputs.skip_build != 'true'
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.parse_inputs.outputs.release_tag }}
release_name: ${{ steps.parse_inputs.outputs.release_tag }}
body: ${{ steps.create_release_notes.outputs.release_notes }}
build-android-apk:
name: Build Android APK
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'android') || contains(needs.prepare.outputs.platforms, 'mobile')) && (needs.prepare.outputs.android_build_type == 'apk' || needs.prepare.outputs.android_build_type == 'both')
uses: ./.github/workflows/android.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
build_number: ${{ needs.prepare.outputs.build_number }}
build_type: apk
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
build-android-aab:
name: Build Android AAB
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'android') || contains(needs.prepare.outputs.platforms, 'mobile')) && (needs.prepare.outputs.android_build_type == 'appbundle' || needs.prepare.outputs.android_build_type == 'both')
uses: ./.github/workflows/android.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
build_number: ${{ needs.prepare.outputs.build_number }}
build_type: appbundle
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
build-ios:
name: Build iOS
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'ios') || contains(needs.prepare.outputs.platforms, 'mobile'))
uses: ./.github/workflows/ios.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
build_number: ${{ needs.prepare.outputs.build_number }}
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
build-macos:
name: Build macOS
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'macos') || contains(needs.prepare.outputs.platforms, 'desktop'))
uses: ./.github/workflows/macos.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
arch: ${{ needs.prepare.outputs.macos_arch }}
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
build-windows:
name: Build Windows
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'windows') || contains(needs.prepare.outputs.platforms, 'desktop'))
uses: ./.github/workflows/windows.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
build-linux:
name: Build Linux
needs: prepare
if: needs.prepare.outputs.skip_build != 'true' && (contains(needs.prepare.outputs.platforms, 'all') || contains(needs.prepare.outputs.platforms, 'linux') || contains(needs.prepare.outputs.platforms, 'desktop'))
uses: ./.github/workflows/linux.yaml
with:
repo: AppFlowy-IO/AppFlowy-Premium
branch: ${{ needs.prepare.outputs.branch_name }}
build_name: ${{ needs.prepare.outputs.version }}
internal_build: ${{ needs.prepare.outputs.internal_build }}
upload_url: ${{ needs.prepare.outputs.upload_url }}
secrets: inherit
# notify-failure:
# runs-on: ubuntu-latest
# needs: [build-android-apk, build-android-aab, build-ios, build-macos, build-windows, build-linux]
# if: failure()
# steps:
# - uses: 8398a7/action-slack@v3
# with:
# status: ${{ job.status }}
# text: |
# 🔴🔴🔴 Workflow ${{ github.workflow }} in repository ${{ github.repository }} failed 🔴🔴🔴
# Version: ${{ needs.prepare.outputs.version }}
# Branch: ${{ needs.prepare.outputs.branch_name }}
# Platforms: ${{ needs.prepare.outputs.platforms }}
# fields: repo,message,author,eventName,ref,workflow
# env:
# SLACK_WEBHOOK_URL: ${{ secrets.RELEASE_SLACK_WEBHOOK }}
# if: always()
notify-success:
runs-on: ubuntu-latest
needs:
[
prepare,
build-android-apk,
build-android-aab,
build-ios,
build-macos,
build-windows,
build-linux,
]
if: success() && needs.prepare.outputs.skip_build != 'true'
steps:
- uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
✅ Release build completed successfully!
**Version:** ${{ needs.prepare.outputs.version }}
**Release Tag:** ${{ needs.prepare.outputs.release_tag }}
**Branch:** ${{ needs.prepare.outputs.branch_name }}
**Platforms:** ${{ needs.prepare.outputs.platforms }}
📦 Check the release at: https://github.com/${{ github.repository }}/releases/tag/${{ needs.prepare.outputs.release_tag }}
fields: repo,message,commit,author,eventName,ref,workflow,job,took
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: always()