Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
347 changes: 311 additions & 36 deletions .github/workflows/flutter-ci.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,73 @@
name: Flutter CI
name: Build and Release Artifacts

on:
pull_request:
paths:
- ".github/workflows/flutter-ci.yml"
- "README.md"
- "flutter_app/**"
push:
branches:
- main
tags:
- "v*"
paths:
- ".github/workflows/flutter-ci.yml"
- "README.md"
- "flutter_app/**"
workflow_dispatch:
inputs:
release_tag:
description: "Optional tag to create/update a GitHub Release for this build, for example v1.0.0."
required: false
type: string
prerelease:
description: "Mark a manually created GitHub Release as a pre-release."
required: false
default: true
type: boolean

permissions:
contents: write

env:
FLUTTER_CHANNEL: stable
FLUTTER_APP_DIR: flutter_app

jobs:
flutter:
name: Test and build Flutter app
validate:
name: Validate Flutter app
runs-on: ubuntu-latest
defaults:
run:
working-directory: flutter_app

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Resolve Flutter dependencies
run: flutter pub get

- name: Check formatting
run: dart format --output=none --set-exit-if-changed lib test

- name: Analyze Flutter app
run: flutter analyze

- name: Run Flutter tests
run: flutter test

build-android:
name: Build Android APK
runs-on: ubuntu-latest
needs: validate
defaults:
run:
working-directory: flutter_app
Expand All @@ -36,14 +85,11 @@ jobs:
distribution: temurin
java-version: "21"

- name: Install Flutter stable
run: |
FLUTTER_ROOT="$RUNNER_TOOL_CACHE/flutter-stable"
rm -rf "$FLUTTER_ROOT"
git clone --depth 1 --branch stable https://github.com/flutter/flutter.git "$FLUTTER_ROOT"
echo "FLUTTER_ROOT=$FLUTTER_ROOT" >> "$GITHUB_ENV"
echo "$FLUTTER_ROOT/bin" >> "$GITHUB_PATH"
"$FLUTTER_ROOT/bin/flutter" --version
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Install Android SDK packages
run: |
Expand All @@ -55,43 +101,272 @@ jobs:
- name: Resolve Flutter dependencies
run: flutter pub get

- name: Check formatting
run: dart format --output=none --set-exit-if-changed lib test

- name: Analyze Flutter app
run: flutter analyze

- name: Run Flutter tests
run: flutter test

- name: Build Android debug APK
run: flutter build apk --debug

- name: Build Android release APK
run: flutter build apk --release

- name: Stage Android release APK
- name: Stage Android artifact
run: |
set -euo pipefail
version="$(awk '/^version:/ { print $2 }' pubspec.yaml | tr '+' '-')"
mkdir -p "$RUNNER_TEMP/studyos-agent"
cp build/app/outputs/flutter-apk/app-release.apk \
"$RUNNER_TEMP/studyos-agent/studyos-agent-android-release.apk"
"$RUNNER_TEMP/studyos-agent/studyos-agent-${version}-android.apk"
(cd "$RUNNER_TEMP/studyos-agent" && sha256sum "studyos-agent-${version}-android.apk" > "studyos-agent-${version}-android.apk.sha256")

- name: Upload Android APK
uses: actions/upload-artifact@v7
with:
name: studyos-agent-android-apk
path: ${{ runner.temp }}/studyos-agent/*
if-no-files-found: error

build-web:
name: Build Web bundle
runs-on: ubuntu-latest
needs: validate
defaults:
run:
working-directory: flutter_app

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Resolve Flutter dependencies
run: flutter pub get

- name: Build web app
run: flutter build web --release

- name: Stage web artifact
run: |
set -euo pipefail
version="$(awk '/^version:/ { print $2 }' pubspec.yaml | tr '+' '-')"
artifact="$RUNNER_TEMP/studyos-agent-web-${version}.zip"
(cd build/web && zip -r "$artifact" .)
sha256sum "$artifact" > "$artifact.sha256"

- name: Upload web bundle
uses: actions/upload-artifact@v7
with:
name: studyos-agent-web
path: |
${{ runner.temp }}/studyos-agent-web-*.zip
${{ runner.temp }}/studyos-agent-web-*.zip.sha256
if-no-files-found: error

build-linux:
name: Build Linux x64 bundle
runs-on: ubuntu-latest
needs: validate
defaults:
run:
working-directory: flutter_app

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install Linux build dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev

- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Enable Linux desktop
run: flutter config --enable-linux-desktop

- name: Resolve Flutter dependencies
run: flutter pub get

- name: Build Linux app
run: flutter build linux --release

- name: Stage Linux artifact
run: |
set -euo pipefail
version="$(awk '/^version:/ { print $2 }' pubspec.yaml | tr '+' '-')"
artifact="$RUNNER_TEMP/studyos-agent-${version}-linux-x64.tar.gz"
tar -C build/linux/x64/release -czf "$artifact" bundle
sha256sum "$artifact" > "$artifact.sha256"

- name: Upload Linux bundle
uses: actions/upload-artifact@v7
with:
name: studyos-agent-linux-x64
path: |
${{ runner.temp }}/studyos-agent-*-linux-x64.tar.gz
${{ runner.temp }}/studyos-agent-*-linux-x64.tar.gz.sha256
if-no-files-found: error

build-macos:
name: Build macOS app
runs-on: macos-latest
needs: validate
defaults:
run:
working-directory: flutter_app

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Upload Android APK artifact
- name: Enable macOS desktop
run: flutter config --enable-macos-desktop

- name: Resolve Flutter dependencies
run: flutter pub get

- name: Build macOS app
run: flutter build macos --release

- name: Stage macOS artifact
run: |
set -euo pipefail
version="$(awk '/^version:/ { print $2 }' pubspec.yaml | tr '+' '-')"
artifact="$RUNNER_TEMP/studyos-agent-${version}-macos.zip"
ditto -c -k --sequesterRsrc --keepParent \
build/macos/Build/Products/Release/studyos_agent.app \
"$artifact"
shasum -a 256 "$artifact" > "$artifact.sha256"

- name: Upload macOS app
uses: actions/upload-artifact@v7
with:
name: studyos-agent-android-release-apk
path: ${{ runner.temp }}/studyos-agent/studyos-agent-android-release.apk
name: studyos-agent-macos
path: |
${{ runner.temp }}/studyos-agent-*-macos.zip
${{ runner.temp }}/studyos-agent-*-macos.zip.sha256
if-no-files-found: error

- name: Attach APK to GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
build-windows:
name: Build Windows x64 app
runs-on: windows-latest
needs: validate
defaults:
run:
working-directory: flutter_app

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_CHANNEL }}
cache: true

- name: Enable Windows desktop
run: flutter config --enable-windows-desktop

- name: Resolve Flutter dependencies
run: flutter pub get

- name: Build Windows app
run: flutter build windows --release

- name: Stage Windows artifact
shell: pwsh
run: |
$version = (Select-String -Path pubspec.yaml -Pattern '^version:\s*(\S+)' | ForEach-Object { $_.Matches[0].Groups[1].Value }).Replace('+', '-')
$artifact = "$env:RUNNER_TEMP\studyos-agent-$version-windows-x64.zip"
Compress-Archive -Path build\windows\x64\runner\Release\* -DestinationPath $artifact -Force
Get-FileHash -Algorithm SHA256 $artifact | ForEach-Object { "$($_.Hash.ToLower()) $(Split-Path $artifact -Leaf)" } | Set-Content "$artifact.sha256"

- name: Upload Windows app
uses: actions/upload-artifact@v7
with:
name: studyos-agent-windows-x64
path: |
${{ runner.temp }}/studyos-agent-*-windows-x64.zip
${{ runner.temp }}/studyos-agent-*-windows-x64.zip.sha256
if-no-files-found: error

release:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs:
- build-android
- build-web
- build-linux
- build-macos
- build-windows
if: github.event_name != 'pull_request'

steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 2

- name: Decide whether to publish
id: release
env:
INPUT_RELEASE_TAG: ${{ inputs.release_tag }}
run: |
set -euo pipefail

if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
release_tag="$GITHUB_REF_NAME"
elif [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" && -n "${INPUT_RELEASE_TAG:-}" ]]; then
release_tag="$INPUT_RELEASE_TAG"
elif [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" ]]; then
current_version="$(awk '/^version:/ { print $2 }' flutter_app/pubspec.yaml)"
previous_version="$(git show HEAD^:flutter_app/pubspec.yaml 2>/dev/null | awk '/^version:/ { print $2 }' || true)"
if [[ -z "$current_version" || "$current_version" == "$previous_version" ]]; then
echo "should_publish=false" >> "$GITHUB_OUTPUT"
exit 0
fi
release_tag="v$current_version"
else
echo "should_publish=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "release_tag=$release_tag" >> "$GITHUB_OUTPUT"

- name: Download build artifacts
if: steps.release.outputs.should_publish == 'true'
uses: actions/download-artifact@v7
with:
path: ${{ runner.temp }}/studyos-release
merge-multiple: true

- name: Publish release artifacts
if: steps.release.outputs.should_publish == 'true'
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.release.outputs.release_tag }}
INPUT_PRERELEASE: ${{ inputs.prerelease }}
run: |
gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1 || \
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--notes "StudyOS Agent Android release for $GITHUB_REF_NAME."
gh release upload "$GITHUB_REF_NAME" \
"$RUNNER_TEMP/studyos-agent/studyos-agent-android-release.apk" \
set -euo pipefail

release_args=(--title "$RELEASE_TAG" --notes "StudyOS Agent builds for $RELEASE_TAG." --target "$GITHUB_SHA")
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" && "${INPUT_PRERELEASE:-false}" == "true" ]]; then
release_args+=(--prerelease)
fi

gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \
gh release create "$RELEASE_TAG" "${release_args[@]}"
gh release upload "$RELEASE_TAG" \
"$RUNNER_TEMP"/studyos-release/* \
--clobber
Loading
Loading